How To – Find All DPS missing NO_SMS_ON_DRIVE on C:\ – And Fix it

C:\ Drive on my DP ran out of space… again…

Something that constantly comes up is forgetting to place the NO_SMS_ON_DRIVE.SMS file on new distribution point servers. While this isn’t the end of the world its certainly frustrating when the C:\ drive runs out of space. Just in case you don’t know what I’m talking about, the NO_SMS_ON_DRIVE.SMS file is a feature of Configuration Manager that has been around for quite a while. This file is what informs the distribution point role to not create a content library on a specific drive.

Gathering DP Information

The first thing we need to do is get our distribution point information. We can do this one of two ways. We can either get all of the distribution points using ConfigMgr cmdlets, or we can use raw WMI queries. I will showcase both methods.

First we need to gather our distribution points and the drives attached to them. We can do this via WMI or the ConfigMgr cmdlets but WMI is more efficient. Let’s start simple with the below code. This code will use the distinct ServerName property for all of your distribution points and return one copy of each DP.

$SiteCode = "YourSiteCode
$ConfigMgrServer = "ConfigMgr Server"
$DPList = Get-WmiObject -ComputerName $ConfigMgrServer -Namespace root\sms\site_$SiteCode -Query "select distinct ServerName from sms_distributionpointInfo"
$DPList

Now we have all our DPS , however if you’ve worked with this WMI section before you know that if we didn’t filter, we would get entries for EVERY drive on each of those DPS without the SMS on Drive Filter. Thats something we don’t want yet. Now all we need to do is iterate through the list of DP’s and check to see if C:\ has the NO_SMS_ON_Drive.SMS file present.

ForEach($DP in $DPList){
   $Result = Test-Path -Path "filesystem::\\$($DP.ServerName)\C$\NO_SMS_ON_DRIVE.SMS"
   Write-Verbose -Message "The Server $($DP.ServerName) returned $($Result) for having the NO_SMS_ON_DRIVE.SMS" -Verbose
}

This will return what servers have and do not have the SMS on drive file.

We found the servers missing it can we fix it?

This leads us to, but can we FIX it remotely with PowerShell? Well sure we can lets start by collecting our information a little more “elegantly”

$SiteCode = "PR1"
$ConfigMgrServer = "PROBRESCM01"
#The dynamic variable works if the admin console is installed in the same directory however I've seen instances of it being installed in X86 and configmgr is in Program Files. 
#$SerVerToolsPath = $(split-path(Split-Path(split-path $env:SMS_ADMIN_UI_PATH)))\tools\ServerTools
$SerVerToolsPath = "C:\Program Files\Microsoft Configuration Manager\tools\ServerTools"



$DPList = Get-WmiObject -ComputerName $ConfigMgrServer -Namespace root\sms\site_$SiteCode -Query "select distinct ServerName from sms_distributionpointInfo"
$Status = New-Object System.Collections.ArrayList
ForEach($DP in $DPList){
   $Result = Test-Path -Path "filesystem::\\$($DP.ServerName)\C$\NO_SMS_ON_DRIVE.SMS"
   Write-Verbose -Message "The Server $($DP.ServerName) returned $($Result) for having the NO_SMS_ON_DRIVE.SMS" -Verbose
   $hash = [ordered]@{
        SERVERNAME = $DP.ServerName
        RESULT = $Result
   }
   $CurrentObject = New-Object -TypeName PSObject -Property $hash
   $Status.Add($CurrentObject) | Out-Null
}

This collects all of our information and builds it into an array list object. Now the first step to migrating content is to copy the needed tools to the destination server. That’s easy enough.

$Status | Where-Object {$_.Result -eq $false} | ForEach-Object {Copy-item -Container $SerVerToolsPath -Recurse -Destination "filesystem::\\$($_.ServerName)\C$\"}

#Note that in the above two scripts I have provided the location for the ServerTools folder and used it as a variable. OK Now we just need to MOVE the content remotely on all of those servers.

Considerations before the move

Some IMPORTANT things to consider before this next part of the script.

  • Make sure the distribution points in question are in Maint Mode
  • Make sure no active distribution of content is occurring for those DP’s
  • This script is focused on getting content OFF of C:\ if you need to address this for multiple drives you WILL need to edit this script.

Now with those little disclaimers and info blocks out there how do we remotely invoke the command to start the transfer?

$Status | Where-Object {$_.Result -eq $false} | ForEach-Object {Invoke-Command -ComputerName $ConfigMgrServer -ScriptBlock {C:\ServerTools\contentlibrarytransfer.exe -SourceDrive E -TargetDrive C} -AsJob}

This example line is assuming your DP content is being moved from a drive C to drive E. Obviously you can change this by just changing the drive letters above. So now our jobs are running but we probably want to know when they are done right?

Do{
    $JobStates = $Status | Where-Object {$_.Result -eq $false} | ForEach-Object {Get-Job | Where-Object {$_.Location -match $_.ServerName}}
    Write-Progress -Activity "Content Migration" -CurrentOperation "$(($JobStates.State | Where-Object {$_ -eq "Completed"}).Count) / $(($JobStates.State).Count) jobs have completed"   -PercentComplete $($(($JobStates.State).Count)/(($JobStates.State | Where-Object {$_ -eq "Completed"}).Count + 1) * 100)
    Start-Sleep -Seconds 60
} 
Until(($JobStates.State | Where-Object {$_ -ne "Completed"}).Count -eq 0)
Write-Verbose -Message "Content migration has finished now returning the results from each job. The result SHOULD be 'Content Library Transfer is now complete' if NOT please review the log generated for that servers session" -Verbose
ForEach($Job in $JobStates){
    $Content = Receive-Job -id $Job.Id
    if($Content[$($Content.Length - 3)] -match "Content Library Transfer is now complete !!" ){
        Write-Verbose -Message "$($Job.Location) returned a positive result" -Verbose
    }
    else{
        Write-Warning -Message "$($Job.Location) returned a NEGATIVE result inspect this job" -WarningAction Continue
    }
    Out-File -FilePath $PSScriptRoot\$($Job.Location).LOG -InputObject $Content
}

So we track the jobs! We get the state of all the powerShell jobs and we check to see if all the jobs we just created are done yet. Now, there are some issues with the way this loop ends – it’s assume we only get “completed” or “running” – so far in testing I’ve never seen it “fail” as failure of the content migration returns a completed status. Of course it’s nice to know that it’s working so a progress bar is included.

This leads to other challenges of course. To address that, I’ve added a section to return the content of the job and check the third line from the bottom to see if it has the proper completed message. If it does life is grand and if it’s not, then it spits out the logs. While you could just run this script as you see it written above I recently had to do this for 19 distribution points which had the content scattered all over… I decided that if possible I would rather not do that again and so I gave the script some parameters. Below is an example of the script migrating content from one drive to the other in my lab.

Parameters

.PARAMETER SITECODE This parameter is for entering the site code of your Configuration Manager server. This allows you to run the script from a device that is not your primary.


.PARAMETER ConfigMgrServer This parameter is for entering the site server that you want to get all the distribution points for and correct.


.PARAMETER ServerToolsPath This parameter is for entering the location of the ServerTools directory. It is copied to the SOURCE drive where you are moving your content library AWAY from


.PARAMETER SourceDrive This paremeter specified the source drive letter. DO NOT use a colon symbol or it will fail.


.PARAMETER DestinationDrive This paremeter specified the destination drive letter. DO NOT use a colon symbol or it will fail.


.PARAMETER MigrateContent This parameter is a switch that in enables the migration aspect of the script. Without this switch the content will not be migrated just reported on if the NO_SMS_ON_DRIVE is missing.

With all of this being said we can now output a finalized version of the script. Which you can download here:

https://github.com/JordanTheITGuy/PowerShell/tree/master/BlogPosts/HowTo%20-%20Find%20All%20DPS%20Missing%20NO_SMS_ON_DRIVE

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: