Friday, October 31, 2008

Defrag Your Servers Remotely with PowerShell

Another quick and dirty script.  I've got a couple servers that are running applications that suffer from disk thrashing, and are running Windows Server 2003.  A defrag tends to noticeably increase performance.  With this script I can kick off a defrag from my desk whenever I want.

Friday, October 3, 2008

Get-SmsWmi and Find-SmsID

I work with SMS (Systems Management Server) at work a lot, so I whipped up two functions that I've found invaluable for automating tasks in SMS, which I alluded to briefly in this post, which contains the source for the functions.

I thoght I'd post today about how these can be used and why they would be useful.  Think of it as the beginnings of a Get-SmsWmi cookbook.

Note:  I alias Get-SmsWmi to 'gsms', so keep that in mind for the examples.

Get a list of all available object nicknames.

C:\PSScripts> gsms

ERROR: You must enter a class name or nickname.

Valid nicknames are:


Note: You only need to type as many characters as necessary to be unambiguous.

Get all computers with 'tojo' in the name.

gsms sys 'Name LIKE "%tojo%"' |
  Format-List ResourceId, 

ResourceId          : 220647
Name                : SOMETOJO-CORP
LastLogonUserName   : sometojo
LastLogonUserDomain : MYDOMAIN
IPAddresses         : {}

Get all advertisements for the package with PackageID 'S01002BE'

gsms adv 'PackageId = "S00002BE"' |
  select AdvertisementID,
  @{Name = 'PackageName'; Expression = {(Find-SmsId -p 'S00002BE').Name}},
  ProgramName |

AdvertisementID   : MV12071F
AdvertisementName : iPass Upgrade
PackageName       : iPass Upgrade
PackageID         : S00002BE
ProgramName       : Update iPass

Delete all packages for a particular distribution point.

gsms pack 'ServerNALPath LIKE "%servername%"' | % {$_.Delete()}

Get a directory listing of all Collections and their subcollections.

# Get-SmsCollectionTree
# Writes an indented list of collecitons by parent
# Args:
#   $root: The CollectionID of the parent collection
#   $indent: The indentation level for screen output

function Get-SmsCollectionTree {
  param([string]$root = 'COLLROOT',
        [int]$indent = 0)

  Get-SmsWmi SMS_CollectToSubCollect "parentCollectionID = '$root'" |
    % {$name =  (Find-SmsID -c $_.subCollectionID).Name
       Add-Member -InputObject $_ -Name 'sub_name' NoteProperty $name
       $_} |
      sort sub_name |
        % {Write-Host (('    ' * $indent) +
                        "+ $($_.sub_name) : $($_.subCollectionID)")
           Get-CollectionTree $_.subCollectionID ($indent + 1)}

Add all packages to a DP.

$dp = gsms SMS_SystemResourceList 'ServerName = "sms-dp-01" and RoleName = "SMS Distribution Point"'

foreach ($pkg in (gsms package)) {
  $new_object = ([wmiclass]"\\sms_srv\root\sms\site_MV1:SMS_DistributionPoint").CreateInstance()
  $new_object.ServerNALPath = $server.NALPath
  $new_object.PackageID = $pkg.PackageID
  $new_object.SiteCode = 'S00'
  $new_object.SiteName = 'My SMS Site'

Note:  That wmiclass/CreateInstance trick I did isn't very well documented, but if you need to create an instance of a class then that's how you can do it.  Also remember that when reading and writing to WMI for SMS, you should be connecting to the server with the SMS Provider, not necessarily the site server.  If you have a separate SQL Server then it might be that server.

That's it for today, but you can see how easy it is to start grabbing data directly from WMI and using it in a script.  If you have any questions drop them in the comments or shoot me an email, I don't get that much traffic.

For a complete list of the WMI classes, download the Configuration Manager 2007 SDK.