Trevor Sullivan's Tech Room

Minding the gap between administration and development

Posts Tagged ‘code’

PowerShell: Finding Friday the 13th

Posted by Trevor Sullivan on 2012/01/13

Update (2012-01-13): Justin Dearing (aka @zippy1981) informed me that it would be more efficient to look at the 13th of each month, and test if it was a Friday. In theory at least, he’s absolutely correct; I wrote the function the first way I thought of it, and I always welcome suggested improvements.

This morning I noticed that it was Friday the 13th. No, I didn’t realize it by looking at the Windows 7 system clock. I realized it because I had the worst morning waking up for the past month. I started wondering when the next Friday the 13th would be, and how often they occurred. To satisfy my curiosity, I immediately thought to write a PowerShell advanced function to find them! This was also partially inspired by Jeff Hicks’ posting 13 PowerShell scriptblocks for Friday the 13th.

There are two parameters to this function:

  • StartDate (default to "today")
  • EndDate (default to "today" +1460 days, which is roughly 4 years in the future)

You can call this function using neither parameter, one of them, or both of them. Both parameters are [System.DateTime] structs, and PowerShell will automatically try to parse any string value passed into them. Here is an example:

Find-Friday13th -StartDate 2000-01-01 -EndDate 2005-01-01

And here is the function!

    This function finds Friday the 13ths.

    .Parameter StartDate
    The date you want to begin searching for Friday the 13ths.
    .Parameter EndDate
    The end date you want to search for Friday the 13ths.

    [System.DateTime] objects that represent Friday the 13ths.

    Written by Trevor Sullivan ( on Friday, January 13, 2012.
function Find-Friday13th {
    param (
        [DateTime] $EndDate = ((Get-Date) + ([TimeSpan]::FromDays(1460)))
        , [DateTime] $StartDate = (Get-Date)

    # Inform user that the $EndDate parameter value must be greater than the $StartDate parameter value
    if ($EndDate -lt $StartDate) {
        Write-Error -Message 'The EndDate must be greater than the StartDate!';

    # Get the next Friday after $StartDate
    while ($StartDate.DayOfWeek -ne 'Friday') {
        Write-Host "Finding next Friday";
        $StartDate = $StartDate.Add([TimeSpan]::FromDays(1));

    # While $StartDate is less than $EndDate, add 7 days
    while ($StartDate -lt $EndDate) {
        # If the Day # is 13, then write the [DateTime] object to the pipeline
        if ($StartDate.Day -eq 13) {
            Write-Output -InputObject $StartDate;
        # Add 7 days to $StartDate (next Friday after current)
        $StartDate = $StartDate.Add([TimeSpan]::FromDays(7));

# Call the function
Find-Friday13th -EndDate 2017-12-31


Here’s what the function’s output looks like. The objects returned to the pipeline are all [System.DateTime] objects, which are automatically being ToString()’d.


Posted in .NET, powershell, scripting | Tagged: , , , , , , , , | 2 Comments »

PowerShell: Move ConfigMgr Collections

Posted by Trevor Sullivan on 2012/01/12


If you work with Microsoft System Center Configuration Manager (SCCM / ConfigMgr) 2007 in any capacity, you probably are familiar with the concept of "collections" and how painful they can be to work with sometimes. The ConfigMgr console does not provide any method of moving a collection from one parent to another, and the GUI is pretty slow to work with.


So what’s the solution here? PowerShell, of course!

PowerShell Code

Here is a PowerShell function that will allow you to move a ConfigMgr collection either by name or by collection ID.

Note: Select all of the function text top-to-bottom, and you can retrieve the text that is cut off towards the right.

    This function allows you to re-assing the parent for a ConfigMgr collection to a new collection ID

    Trevor Sullivan (

    c:\PS> Move-SccmCollection -SccmServer sccm01 -SiteCode LAB -CollectionID LAB00159 -ParentCollectionID LAB000150;


    This command moves the ConfigMgr collection with ID "LAB000159" to being a child of collection ID "LAB000150".

    c:\PS> Move-SccmCollection -SccmServer sccm01 -SiteCode LAB -CollectionName 'Visual Studio' -ParentCollectionID Microsoft;


    This command moves the ConfigMgr collection named "Visual Studio" to being a child of the collection named "Microsoft". Note that you do not need to specify quotes around the parameter value if it does not contain spaces.

    This function is untested with collection links. It is not known whether or not this will remove existing collection links.
function Move-SccmCollection {
    param (
        [Parameter(Mandatory = $true)] [string] ${SccmServer}
        , [Parameter(Mandatory = $true)] [string] ${SiteCode}
        , [Parameter(ParameterSetName = "ByCollectionID", Mandatory = $true)] [string] ${CollectionID}
        , [Parameter(ParameterSetName = "ByCollectionID", Mandatory = $true)] [string] ${ParentCollectionID}
        , [Parameter(ParameterSetName = "ByCollectionName", Mandatory = $true)] [string] ${CollectionName}
        , [Parameter(ParameterSetName = "ByCollectionName", Mandatory = $true)] [string] ${ParentCollectionName}

    # Set-PSDebug -Strict;

    # Ensure that ConfigMgr site server is available
    if (-not (Test-Connection -ComputerName $SccmServer -Count 1)) {

    # Obtain references to collection and parent collection
    switch ($PSCmdlet.ParameterSetName) {
        # Use the "ByCollectionID" PowerShell parameter set to retrieve collection references by ID
        'ByCollectionID' {
            ${CollectionRelationship} = @(Get-WmiObject -ComputerName $SccmServer -Namespace root\sms\site_$SiteCode -Class SMS_CollectToSubCollect -Filter "subCollectionID = '$CollectionID'")[0];
            ${Collection} = @([wmi]("\\{0}\root\sms\site_{1}:SMS_Collection.CollectionID='{2}'" -f ${SccmServer}, ${SiteCode}, ${CollectionID}))[0];
            ${ParentCollection} = @([wmi]("\\{0}\root\sms\site_{1}:SMS_Collection.CollectionID='{2}'" -f ${SccmServer}, ${SiteCode}, ${ParentCollectionID}))[0];
        # Use the "ByCollectionName" PowerShell parameter set to retrieve collection references by name
        'ByCollectionName' {
            ${Collection} = [wmi](@(Get-WmiObject -ComputerName $SccmServer -Namespace root\sms\site_$SiteCode -Class SMS_Collection -Filter ("Name = '{0}'" -f ${CollectionName}))[0].__PATH);
            ${ParentCollection} = [wmi](@(Get-WmiObject -ComputerName $SccmServer -Namespace root\sms\site_$SiteCode -Class SMS_Collection -Filter ("Name = '{0}'" -f ${ParentCollectionName}))[0].__PATH);
            ${CollectionRelationship} = @(Get-WmiObject -ComputerName $SccmServer -Namespace root\sms\site_$SiteCode -Class SMS_CollectToSubCollect -Filter ("subCollectionID = '{0}'" -f ${Collection}.CollectionID))[0];
    # If references to both the child and [new] parent collection were obtained, then move on
    if (${Collection} -and ${ParentCollection}) {
        Write-Verbose -Message ('Setting parent collection for {0}:{1} to {2}:{3}' -f `
            ${Collection}.CollectionID `
            , ${Collection}.Name `
            , ${ParentCollection}.CollectionID `
            , ${ParentCollection}.Name);
        ${CollectionRelationship}.parentCollectionID = ${ParentCollection}.CollectionID;
        # Create the new collection relationship (this [oddly] spawns a NEW instance of SMS_CollectToSubCollect), so we have to clean up the original one

        # Clean up all other collection relantionships for this collection
        ${OldCollectionRelationshipList} = @(Get-WmiObject -ComputerName $SccmServer -Namespace root\sms\site_$SiteCode -Class SMS_CollectToSubCollect -Filter ("subCollectionID = '{0}' and parentCollectionID <> '{1}'" -f ${Collection}.CollectionID, ${ParentCollection}.CollectionID));
        foreach (${OldCollectionRelationship} in ${OldCollectionRelationshipList}) {
    else {
        Write-Warning -Message 'Please ensure that you have entered a valid collection ID or name';


Here is an example of how to use this function to move a collection based on their collection IDs:

Move-SccmCollection -SccmServer sccm01.mybiz.loc -SiteCode LAB -CollectionID LAB00011 -ParentCollectionID LAB00022;

Here is an example of how to use the function to move a collection based on the collection name:

Move-SccmCollection -SccmServer sccm01.mybiz.loc -SiteCode LAB -CollectionName ‘Visual Studio’ -ParentCollectionID Microsoft;

Posted in configmgr, powershell, scripting, tools, wmi | Tagged: , , , , , , , , , , , , , , , , | Leave a Comment »

Uploading a Video to Youtube via PowerShell

Posted by Trevor Sullivan on 2010/03/09

Hey guys! I know it’s been a long time since I have posted anything useful (that is, assuming anything I post is useful! haha). While sitting at Starbucks today, I suddenly came up with an idea for a new post though, and after doing a quick bit of research, figured I would write about it! The purpose of today’s post is to show an example of using PowerShell to upload a video to Youtube! This could be useful in a variety of circumstances, but I’ll leave finding the use cases up to each of you individually 🙂 A couple of examples I can think of would be:

  • Batch uploading a folder of videos
  • Automating the upload of videos that may be somehow generated into a folder automatically
  • …. ???

In any event, in my search to find a solution, knowing that PowerShell is based on the Microsoft .NET Framework, I searched for “C# upload youtube”. One of the first results that came up was a blog called “Trails in the Sand,” and more specifically, a post entitled “Programmatically Uploading Videos to Youtube.” This blog article goes into detail about uploading videos to Youtube using C#/.NET, but at the bottom of the post, the author was kind enough to include the source code for a library he had written! As a PowerShell scripter, you’ve probably learned to be very thankful for other people who write and share .NET libraries to do “cool stuff!”

After downloading the “Trails in the Sand Youtube Library,” I opened it up in Visual C# 2008 Express Edition (free, fully-functional version of Visual Studio), and converted the project to Visual Studio 2008 format, using the wizard that pops up. The conversion was successful, so I proceeded to create a developer key for Youtube. You can generate your own developer key at the following URL:

After pasting my developer key into the project under the “devCode” string constant, I compiled the library by hitting “F6.” This created my library under the “bin\release” folder of the project. Next, I opened Quest’s PowerGUI (a great, free PowerShell editor), and started a new script. First things first, using the System.Reflection.Assembly .NET class, I loaded the newly created .NET Youtube library into PowerShell:


Next, I instantiated the Trails.YouTube object:

$Yt = New-Object Trails.YouTube

Once I had the YouTube object, I defined a string variable to use as an “out” parameter, to capture any resulting error (if you don’t pre-define it, you’ll get an error):

$UploadError = “”

Next, we call the Authorize() method, passing our username and password:

$Yt.Authorize(“username”, “password”)

And then finally, we upload the video using the Upload() method! Parameters are as follows:

  • Title
  • Description
  • Category (library has a spelling error: “catagory”)
  • Video keywords
  • Path to local video file
  • Error variable (pre-defined variable, used as an “out” parameter)

$result = $Yt.Upload(“Test upload”, “test upload”, [Trails.YouTube+Catagory]::Howto, “keyword1”, “C:\Users\trevor.sullivan\Videos\SMS_BootImagePackage.wmv”, [ref] $UploadError)

Optionally, you can print out any resulting error message:


The entire script put together looks like this:

$LibYt = [System.Reflection.Assembly]::LoadFile(“c:\Users\trevor.sullivan\Documents\\YouTube\bin\Release\YouTube.dll”)

$Yt = New-Object Trails.YouTube

$UploadError = “”

$Yt.Authorize($(Read-Host -Prompt “Please enter username”), $(Read-Host -Prompt “Please enter password”))

$result = $Yt.Upload(“Test upload”, “test upload”, [Trails.YouTube+Catagory]::Howto, “keyword1”, “C:\Users\trevor.sullivan\Videos\SMS_BootImagePackage.wmv”, [ref] $UploadError)


If we wanted to “variable-ize” (yes, I made that up just now) this script a bit more, we could do something like this:

### Define YouTube library path

$YtDll = “c:\Users\trevor.sullivan\Documents\\YouTube\bin\Release\YouTube.dll”

### Get YouTube username and password

$YtUser = $(Read-Host -Prompt “Please enter username”)

$YtPass = $(Read-Host -Prompt “Please enter password”)

######## Set up video variables ########

$vTitle = “Video Title”

$vDesc = “Video Description”

$vCat = [Trails.YouTube+Catagory]::Howto

$vKeyword = “keyword1”

$vPath = “C:\Users\trevor.sullivan\Videos\SMS_BootImagePackage.wmv”

$vErr = “”

### Load YouTube library, login, upload video, and echo error

$LibYt = [System.Reflection.Assembly]::LoadFile($YtDll)

$Yt = New-Object Trails.YouTube

$Yt.Authorize($YtUser, $YtPass)

$result = $Yt.Upload($vTitle, $vDesc, $vCat, $vKeyword, $vPath, [ref] $vErr)


Hope this post helps!


Posted in powershell, scripting, tools | Tagged: , , , , , , , , , , , , , | 5 Comments »