Bookmark and Share
 

(Note: These solutions were written for Beginner Event 3 of the 2010 Scripting Games.)
 

Beginner Event 3 (Windows PowerShell)

Image of Marco Shaw

 

Marco Shaw

Windows PowerShell MVP 2008-2010

Blog: http://marcoshaw.blogspot.com/

Twitter: @MarcoShaw

 

With any type of task that involves any kind of repeated action, I have developed the mindset of trying to create a script for it. Ten years ago, I would have just created a file and manually copied it 10 times, but I made a conscious decision years ago to write as many scripts as I could so that I would become more efficient. Now, creating scripts has become so much more simple. I still struggle every time I switch from one scripting language to anther as I script things with Windows PowerShell, but typically with the Borne shell on Linux/UNIX.


Onto the challenge. The first thing I do is fully read the question a few times to make sure I didn’t miss anything. From previous Scripting Games, I’ve come to determine that Ed can be sneaky and try to trick you by leaving out subtle details. This challenge seems to be pretty clearly identified.


The only thing I see needing extra attention is that the resulting filenames are file01,…,file10. So it isn’t a simple 1 to 10 incremental increase, but the numbers need to be padded with a 0 until 10 is reached.


In the past, I would have typically used logic like this to pad small numbers with a 0:


1..10|ForEach-Object{if($_ -lt 10){"0$_"}else{$_}}


And that code would give numbers 01 to 10 as required.


There’s also a more advanced way, and the other method lends itself to more types of customizations. It involves using the -f format operator, which provides string formatting features provided by the Microsoft .NET Framework; however, I’m just going to mention it here, but I will not use that method.


First, I’m going to use a small trick provided by the ForEach-Object cmdlet where there’s actually functionality built in to run three different script blocks: Begin, Process, End:


·        
The Begin script block will be run or evaluated before any items are actually processed from the pipeline.

·         The Process script block will be run or evaluated for every item that is passed along the pipeline.

·         The End script block will be run or evaluated after every item has been passed through the pipeline.


I’m not going to be using an End script block in my case, but I will use the Being and Process. I will use the Begin script block to set up my template file, and then use my Process script block to create the copies:


1..10|ForEach –Begin {cd “c:\fso”;echo “CLASS:” > file;echo “DATE:” >> file;echo “NOTES:” >> file} –Process {$num=if($_ -lt 10){"0$_"}else{$_};copy-item “c:\fso\file” “c:\fso\file$num”}


This achieves the desired results. You may notice that I went with a Linux/UNIX style syntax by using the echo alias, and also the redirection operators > and >>.


Now, what happens if you didn’t use this approach? If you get the correct answer using your own method, your way is just as good. This could have been accomplished in so many different ways, so there’s no single “right answer” in this case. Here is my script:


1..10|ForEach –Begin {
  cd "c:\fso";echo "CLASS:" > file;
  echo "DATE:" >> file
  echo "NOTES:" >> file} `
–Process {
  "Current number: $_"
  $num=if($_ -lt 10){"0$_"}else{$_}
  "Using padded number: $num"
  "Copying c:\fso\file to c:\fso\file$num"
  copy-item "c:\fso\file" "c:\fso\file$num"
}


And here is the result:


Image of result of running script

 

Beginner Event 3 (VBScript)

Image of Scripting Guy Ed Wilson

 

Ed Wilson is one of the Microsoft Scripting Guys and a well-known scripting expert. He writes daily Hey, Scripting Guy! Blog posts and weekly blog posts for Microsoft Press. He has also spoken at Tech·Ed and at the Microsoft internal TechReady conferences. He is a Microsoft Certified Trainer who has delivered a popular Windows PowerShell workshop to Microsoft Premier customers worldwide. He has written nine books, including six about Windows scripting that were published by Microsoft Press. Ed has also contributed to nearly a dozen other books. His Windows PowerShell 2.0 Best Practices book for Microsoft Press was recently published. Ed holds more than 20 industry certifications, including Microsoft Certified Systems Engineer (MCSE) and Certified Information Systems Security Professional (CISSP).


------------


When I read things like “create ten files,” I immediately think I am going to use a looping construction. When I see that my file names are going to be things like file1.txt and file2.txt, I know that I can use concatenation to build the file name. The last thing to decide was how to create the text for the text files. I decided to again use a bit of concatenation, but also to use the VBScript constant vbcrlf to create a carriage return and line feed (new line) after each of the three required lines for the file.


In VBScript, when you need to create a text file, it makes sense to use the Scripting.FileSystem object because it is extremely efficient and relatively easy to use. Because the CreateObject command returns an object, you must use the Set command when calling this line of code. Make sure this line of code appears outside of the For...Next loop, or else you will create the object multiple times, which is inefficient. This line of code is shown here:


Set objFSO = CreateObject("Scripting.FileSystemObject")


After the FileSystemObject has been created, it is time to build the path to the file. To do this, use concatenation as shown in the following line of code. Make sure that you do not forget backward slashes or the file could become created in a strange location:


strFilePath = strPath & "\file" & i & ".txt"


The Wscript.Echo command displays the path to the file after it is created. When the script is run using Cscript, these messages are displayed in the Command Prompt window; if the script is run using Wscript, the messages become popup boxes that must be closed. To avoid this problem, it is worthwhile to check to see which scripting engine is being used. There is no need to close the file after it has been created. You can write directly to the file by using the WriteLine method. The CreateTextFile method returns a file object. This is shown here:


Set objFile = objFSO.CreateTextFile(strFilePath)
objFile.WriteLine(strText)


After the file has been created and the text written to the file, you need to close the file. Do this by using the Close method as shown here:


objFile.Close


The script then loops around, and continues creating the remaining files. The complete BeginnerEvent3.vbs script is seen here.


BeginnerEvent3.vbs

Option Explicit
Dim strPath
Dim objFSO
Dim intFiles
Dim strFilePath
Dim strText
Dim i
Dim objFile

strPath = "C:\fso"
intFiles = 10
strText = "CLASS:" & VbCrLf & "DATE:" & VbCrLf & "NOTES:"

Set objFSO = CreateObject("Scripting.FileSystemObject")
For i = 1 To intFiles
 strFilePath = strPath & "\file" & i & ".txt"
 WScript.Echo "Creating " & strFilePath
 Set objFile = objFSO.CreateTextFile(strFilePath)
 objFile.WriteLine(strText)
 objFile.Close
Next


When you run the script, 10 files are created inside the c:\fso directory. If you do not have a c:\fso directory, change the strPath to point to a different location. The file that gets created is seen in the following image.

Image of file created by script

 

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

 

Ed Wilson and Craig Liebendorfer, Scripting Guys