Share this post:

Hey, Scripting Guy! Question

Hey, Scripting Guy! I hate to type numbers. I actually took typing in high school and did really well with it. I was able to type more than 40 words per minute at the end of the class with no errors. I got an A for the class. But, I was horrible at doing numbers. Maybe it was because we did not practice them as often or maybe it is because I hated math when I was in school. For whatever reason, I think I would rather go to the doctor’s office and give blood than to have to type a document with a bunch of numbers in it.

This background information is intended help you put my request in perspective. We use folders that are set up with the day of year number. Inside each folder numbered with the day of the year, we create a new folder with the day of the year and the two digits of the year appended to it. The folders are in a modified ordinal date format. Needless to say, such a prospect just drives me crazy. Can you write a script that will create a folder that is the next number in the series and append the two year date to it?

-- SC

Hey, Scripting Guy! Answer

Hello SC,

I can sympathize with your aversion, especially because you say you would rather go to the doctor’s office and give blood. Personally, I am allergic to needles, and I break out in a cold sweat when I have to go see the lab person. I would much rather go to San Francisco, California, and head down to Fisherman's Wharf and watch the California sea lions wrestle:

Image of California sea lions 

This week we are looking at questions that have been posted to the Official Scripting Guys Forum. This user forum is a great place to ask questions related to VBScript or Windows PowerShell. It is also an excellent resource to learning scripting by either reading answers to others questions, or by becoming involved in discussions through posting answers. In addition to being a learning resource the forum is also a fun place to interact with people from around the world who have an interest in scripting. The Official Scripting Guys Forum is free, and you can read all questions and answers by going to the web site. If you wish to post a question or propose an answer to a question you will need to log in with your Windows Live ID.

SC, I was recently trolling through the Official Scripting Guys Forum, and I ran across a similar question to yours. The good thing is that Brandon, one of our moderators on the Official Scripting Guys Forum, and a Microsoft MVP for Windows PowerShell had already posted a cleaver answer to the question. This is seen here:

Image of question on forum 


After reading Brandon's answer to the previous question, I decided to play around with his answer, and add some error checking and other things that would make it a cool script for you. The CreateNewFolderWithPattern.ps1 script is seen here.

CreateNewFolderWithPattern.ps1

Param($FolderPath)

Function Test-FolderPath($folderPath)

{

 if(-not(Test-Path -path $folderPath))

   {

     New-Item -path $folderPath -ItemType Directory -force |

     Out-Null

   }

} #end function Test-FolderPath

Function New-CustomFolder($folderPath)

{

 $Parent = Split-Path $FolderPath -Parent

 $Leaf = Split-Path $FolderPath -leaf

 if($leaf -notmatch "\d") { "Folder name must be a number. Such as 55.12 or 12356" ; exit }

 $Folder = Get-item $FolderPath

 $DefaultName = "{0}\{1}.{2}" -f $Parent,([int]($Folder.Name.split(".")[0])+1),(get-date -f yy)

 $NewFolder = Read-Host "Name of New Folder? [Default] $DefaultName"

 if(!$NewFolder)

 {

  $NewFolder = $DefaultName

 }

 if(-not(Test-Path -path $NewFolder))

   { New-Item -ItemType Directory -path $NewFolder }

 Else { "$NewFolder already exists." ; exit }

} #end function New-CustomFolder

# *** Entry Point to Script ***

Test-FolderPath -folderPath $folderPath

New-CustomFolder -folderPath $folderPath

The CreateNewFolderWithPattern.ps1 script begins by creating a command-line parameter. The parameter to be supplied to the script is the path to the parent folder. Because of the unique requirements of this solution, the child folder name must contain only numbers. The param statement is used to create the command-line parameter. This is seen here:

Param($FolderPath)

The first function that is seen in the CreateNewFolderWithPattern.ps1 script is the Test-FolderPath function. This function uses the Test-Path cmdlet to determine if the folder that was supplied via the command line exists on the system. If the folder does not exist, a new folder is created. The force parameter is used to tell Windows PowerShell to create child paths even if the parent paths do not exist. The result of the operation is piped to the Out-Null cmdlet to keep from cluttering the Windows PowerShell console. This is seen here:

Function Test-FolderPath($folderPath)

{

 if(-not(Test-Path -path $folderPath))

   {

     New-Item -path $folderPath -ItemType Directory -force |

     Out-Null

   }

} #end function Test-FolderPath


After the Test-FolderPath function has been created, you turn your attention to the New-CustomFolder function. This function first uses the Split-Path cmdlet to retrieve the parent portion of the path. It next uses the Split-Path function with the leaf parameter to retrieve the child portion of the path name. The last portion of a path to a folder is always the leaf portion. Everything else is the parent portion of the path. Some examples are seen in Table 1.

Table 1  Parent and Leaf Examples

Path

 

Parent

 

Leaf

 

C:\fso

 

C:\

 

Fso

 

C:\fso\fso1

 

C:\fso

 

Fso1

 

C:\fso\fso1\fso2

 

C:\fso\fso1

 

Fso2

 


The two Split-Path commands are seen here:

Function New-CustomFolder($folderPath)

{

$Parent = Split-Path $FolderPath -Parent

 $Leaf = Split-Path $FolderPath -leaf

The script expects the leaf (child path) to be a number. But because the way the path is passed into the parameter, the leaf would always be considered to be a string. This prevents using the is operator to see if the leaf is a string or if it is an integer. The use of the is operator is seen here:

PS C:\> 5 -is [int]

True

PS C:\> "five" -is [string]

True

PS C:\>

After playing around with a few different ideas, I finally decided to use a regular expression pattern match ("\d") to see if the leaf matched a number. If it does not match a number, the leaf is a string and will cause an error when we later attempt to do an op addition. A message stating that the folder name must be a number is displayed and the script exits. This is seen here:

 if($leaf -notmatch "\d") { "Folder name must be a number. Such as 55.12 or 12356" ; exit }


The Get-Item cmdlet is used to retrieve the folder specified by the $FolderPath variable. After the folder object is retrieved and stored in the $Folder variable, the new folder name is generated. The new folder name is created by using the format operator, which accepts a pattern for replacement values. In this example, three replacement items are used: the parent folder path, the name of the leaf folder that is converted into an integer and incremented by one, and a two-digit representation of the current year.


When using the format operator, each value that will be substituted goes inside a pair of curly brackets. The first item to be substituted is {0} and the second one is {1}. The replacement pattern is placed inside a pair of quotation marks. The replacement values are on the right side of the format operator, and these are separated by commas. A simple example consists of a replacement pattern that comprises two items. The two items are separated by a space "{0} {1}" followed by the closing quotation mark. The format operator –f is followed by the two replacement values, Hello and Ed. When the line of code is executed, the string Hello Ed is returned to the console. This is seen here:

PS C:\> "{0} {1}" -f "Hello","Ed"

Hello Ed

PS C:\>

The use of replacement patterns can simplify some of the concatenation that might otherwise be required. It is an elegant solution to a common problem. This is seen here:

 $Folder = Get-item $FolderPath

 $DefaultName = "{0}\{1}.{2}" -f $Parent,([int]($Folder.Name.split(".")[0])+1),(get-date -f yy)

The Read-Host cmdlet is used to prompt the user to use the newly created folder name. If the user chooses to accept the newly created folder name that is stored in the $newFolder variable, it will be assigned to the value of the $DefaultName variable. This is seen here:

 $NewFolder = Read-Host "Name of New Folder? [Default] $DefaultName"

 if(!$NewFolder)

 {

  $NewFolder = $DefaultName

 }

If the script has been run previously, it is possible the folder specified by the $NewFolder path might already exist. To forestall this problem, the Test-Path cmdlet is used as seen here. After it has been determined the folder does not exist, the New-Item cmdlet is used to create a new folder. If the folder does exist, a message stating the folder exists is displayed. This is seen here:

 if(-not(Test-Path -path $NewFolder))

   { New-Item -ItemType Directory -path $NewFolder }

 Else { "$NewFolder already exists." ; exit }

} #end function New-CustomFolder

The entry point of the script calls the Test-FolderPath function to ensure that the parent folder exists. After that is determined, the New-CustomFolder function is called to create the new folder. This is seen here:

Test-FolderPath -folderPath $folderPath

New-CustomFolder -folderPath $folderPath


SC, thank you for your question you sent to scripter@microsoft.com. It was a great question, especially because it had already been answered in the Official Scripting Guys Forum. Join us tomorrow as Script Forum Week continues.

If you want to know exactly what we will be covering tomorrow, follow us on Twitter or Facebook. If you have any questions, send us e-mail at scripter@microsoft.com or post them to the Official Scripting Guys Forum. See you tomorrow. Until then, keep on scripting. 

Ed Wilson and Craig Liebendorfer, Scripting Guys