Hey, Scripting Guy! Can I Pause and Resume Scripts with Windows PowerShell?
Hey Scripting Guy! I am working on a Windows PowerShell script, and I would like to pause the script for three minutes and then resume it. I know I can use the Start-Sleep cmdlet to halt script execution, but I would like to give a visual indication that the script is waiting, and display information on the screen every second that would list how much time is remaining. Is this going to be too hard to do? Should I abandon my attempts at providing user feedback and just go with the Start-Sleep cmdlet?
— BD
Hello BD,
Microsoft Scripting Guy Ed Wilson here. One should never give up hope—otherwise there would be nothing to hope for. Having written thousands of scripts for all kinds of users, I have found that it is a good practice to at least provide the option to get feedback from the user. This is true even for me—if I click something and I do not see something take place, I am likely to click it again and again. If I still don’t see something happen, I am likely to reboot my computer (although this has not been my experience since I installed Windows 7). At a minimum this feedback should be something that says something like this:
Script is working … this may take some time … please wait …
I wrote one script that would write to the registry the amount of time the operation took. The next time the script ran, it would retrieve the information from the registry. The prompt looked something like this:
Beginning process … When this script last ran on 1/5/2009 it took 3:35 seconds to complete.
Please wait …
When the script completed, it displayed the amount of time the script ran and updated the values in the registry. Writing the processing time to the registry is not what you inquired about, although it is a cool technique. What will help you is an egg timer script. I seem to remember something like that from the 2009 Summer Scripting Games. Hold on while I go check.
This week we will be reviewing some of the scripts that were submitted during the recently held 2009 Summer Scripting Games. The description of the 2009 Summer Scripting Games details all of the events. Each of the events was answered by a globally recognized expert in the field. There were some cool prizes and winners were recognized from around the world. Additionally, just like at the “real Olympics” because there was a lot going on, an “if you get lost page” was created. Communication with participants was maintained via Twitter, Facebook, and a special forum. (The special forum has been taken down, but Twitter and Facebook are still used to communicate with Hey, Scripting Guy! fans). We will be focusing on solutions that used Windows PowerShell. We have several good introduction to Windows PowerShell Hey, Scripting Guy! articles that you will find helpful.
The 2009 Summer Scripting Games Beginner Event 10 involved counting down time in an egg timer fashion. BigAlfonso submitted the ScriptingGamesBeginnerEvent10.ps1 script. The complete script, seen here, features a three-minute countdown timer.
ScriptingGamesBeginnerEvent10.ps1
for ($time=180;$time -ge 0;$time–)
{
$min = [math]::floor([int] $time / [int] 60)
$sec = $time % 60
$strmin = $min.tostring()
if ($sec -lt 10)
{$strsec = “0” + $sec.tostring()}
else
{$strsec = $sec.tostring()}
write-host $strmin”:”$strsec
start-sleep 1
}
write-host “Time’s up!!!”
write-host (“`a”*4)
The script begins with a for statement that uses the double-minus operator. A for statement in Windows PowerShell is a looping construction that can be used to walk through a collection, to repeat an operation multiple times, walk through an array, or work with groups of items. It is a useful construction. For a good introduction to using the for statement check out the “Mind-Numbing, Repetitive Tasks” Hey, Scripting Guy! article. In that article, I discussed several ways of using the for statement. One thing, however, that I did not talk about was backtracking. Just as we have the ++ operator that means to take the current value and add one to it, we also have a — operator that means to take the current number and decrement it by one. This is seen here:
for($i=5; $i -ge 0 ; $i–)
{ $i }
When the above construction is run, it produces the output seen here:
5
4
3
2
1
0
The — operator is the perfect tool to use when counting backward, such as when creating an egg timer. The key is making sure your condition is correct. When counting upward, we often want to do something as long as a condition is less than or equal to something. Here we want the condition to prevail as long as the time is greater than zero. This is seen here:
for ($time=180;$time -ge 0;$time–)
One unusual feature of the BigAlfonso script is the use of the [math]::floor() method. A math floor has nothing to do with where you went when you studied differential equations. The floor method of the System.Math .NET Framework class returns the largest integer less than or equal to the specified number. The behavior of this method follows IEEE Standard 754, section 4. This kind of rounding is sometimes called rounding toward negative infinity. The opposite behavior is the [math]::Ceiling() method that is used to return the smallest integer greater than or equal to the specified number. Rounding to the smallest integer is sometimes called rounding toward positive infinity. An example of using the floor method is seen here:
PS C:> [math]::floor(180/60)
3
PS C:> [math]::floor(179/60)
2
PS C:> [math]::floor(119/60)
1
PS C:>
The other interesting part of the BigAlfonso script is the use of the modulo operator. The modulo operator returns what is left over after completing a division operation. For example, 5 modulo 2 would return 1 because 2 goes into 5 twice and leaves one left over. Here are additional examples of modulo division that are more applicable to the egg timer scenario:
PS C:> 180 % 60
0
PS C:> 179 % 60
59
PS C:> 119 % 60
59
PS C:>
The floor method and the modulo operator are seen here:
$min = [math]::floor([int] $time / [int] 60)
$sec = $time % 60
The next thing the script does is convert the number of minutes into a string and assign it to another variable. In Windows PowerShell, it is easy to convert a number to a string. This is seen here where a type constraint is used to ensure the number 5 is an integer. The number is then converted to a string by using the tostring method and the gettype method is used to display the data type that is returned. Not surprisingly, the data type is a string:
PS C:> ([int]5).tostring().GetType()
IsPublic IsSerial Name BaseType
——– ——– —- ——–
True True String System.Object
In the script, the number of minutes that are returned from the floor method is converted to a string with the code seen here:
$strmin = $min.tostring()
The step of converting the number to a string is not required and can be left out. This is because when the number is placed into quotation marks, it automatically gets converted to a string. This will be seen later.
BigAlfonso next uses an if…else construction to determine whether or not to pad the number of seconds. If the number is less than 10 seconds, padding is required; if the number is 10 seconds or greater, no padding is required. This is seen here:
if ($sec -lt 10)
{$strsec = “0” + $sec.tostring()}
else
{$strsec = $sec.tostring()}
Two things remain: Produce output and pause for a second between loops. The Write-Host cmdlet is used to write to the console host, and the Start-Sleep cmdlet is used to pause the script for 1 second. The backtick a (“`a”) produces an alert (beep) sound to the system speaker when the script is run in the Windows PowerShell console, but it only writes a [] in the output when the script is run inside the Windows PowerShell ISE. I love being able to multiple things. If you want to display three a’s, you can use the multiplication technique as seen here:
PS C:> “a”*3
aaa
PS C:>
The output section of the script is seen here:
write-host $strmin”:”$strsec
start-sleep 1
}
write-host “Time’s up!!!”
write-host (“`a”*4)
When the script is run, it produces the output seen here:
To make the countdown timer a bit more useful, you can turn it into a function. The ScriptingGamesBeginnerEvent10Function.ps1 script is essentially the same as the script submitted by BigAlfonso. To turn it into a function, the function keyword is used along with a couple of curly brackets {} for the script block. A couple of minor changes were indicated. The first was to remove the explicit conversion of the integers to strings as mentioned in the earlier discussion. The second thing that was done was to remove the use of the Write-Host cmdlet. Write-Host is not required and most times is to be avoided because it destroys the object that it emits to the console. This is seen here where the “a” on the Windows PowerShell console returns a system.string object. Write-Host does not return anything:
PS C:> “a” | gm
TypeName: System.String
Name MemberType Definition
—- ———- ———-
Clone Method System.Object Clone()
CompareTo Method int CompareTo(System.Object value), int CompareTo(string strB)
Contains Method bool Contains(string value)
CopyTo Method System.Void CopyTo(int sourceIndex, char[] destination, int destinationIndex,..
EndsWith Method bool EndsWith(string value), bool EndsWith(string value, System.StringCompari..
Equals Method bool Equals(System.Object obj), bool Equals(string value), bool Equals(string..
GetEnumerator Method System.CharEnumerator GetEnumerator()
GetHashCode Method int GetHashCode()
GetType Method type GetType()
GetTypeCode Method System.TypeCode GetTypeCode()
IndexOf Method int IndexOf(char value), int IndexOf(char value, int startIndex), int IndexOf..
IndexOfAny Method int IndexOfAny(char[] anyOf), int IndexOfAny(char[] anyOf, int startIndex), i..
Insert Method string Insert(int startIndex, string value)
IsNormalized Method bool IsNormalized(), bool IsNormalized(System.Text.NormalizationForm normaliz..
LastIndexOf Method int LastIndexOf(char value), int LastIndexOf(char value, int startIndex), int..
LastIndexOfAny Method int LastIndexOfAny(char[] anyOf), int LastIndexOfAny(char[] anyOf, int startI..
Normalize Method string Normalize(), string Normalize(System.Text.NormalizationForm normalizat..
PadLeft Method string PadLeft(int totalWidth), string PadLeft(int totalWidth, char paddingChar
PadRight Method string PadRight(int totalWidth), string PadRight(int totalWidth, char padding..
Remove Method string Remove(int startIndex, int count), string Remove(int startIndex)
Replace Method string Replace(char oldChar, char newChar), string Replace(string oldValue, s..
Split Method string[] Split(Params char[] separator), string[] Split(char[] separator, int..
StartsWith Method bool StartsWith(string value), bool StartsWith(string value, System.StringCom..
Substring Method string Substring(int startIndex), string Substring(int startIndex, int length)
ToCharArray Method char[] ToCharArray(), char[] ToCharArray(int startIndex, int length)
ToLower Method string ToLower(), string ToLower(System.Globalization.CultureInfo culture)
ToLowerInvariant Method string ToLowerInvariant()
ToString Method string ToString(), string ToString(System.IFormatProvider provider)
ToUpper Method string ToUpper(), string ToUpper(System.Globalization.CultureInfo culture)
ToUpperInvariant Method string ToUpperInvariant()
Trim Method string Trim(Params char[] trimChars), string Trim()
TrimEnd Method string TrimEnd(Params char[] trimChars)
TrimStart Method string TrimStart(Params char[] trimChars)
Chars ParameterizedProperty char Chars(int index) {get;}
Length Property System.Int32 Length {get;}
PS C:> Write-host “a” | gm
a
Get-Member : No object has been specified to the get-member cmdlet.
At line:1 char:20
+ Write-host “a” | gm <<<<
+ CategoryInfo : CloseError: (:) [Get-Member], InvalidOperationException
+ FullyQualifiedErrorId : NoObjectInGetMember,Microsoft.PowerShell.Commands.GetMemberCommand
A function in Windows PowerShell automatically returns an object to the calling command. Write-Host short-circuits that operation. The last thing I did in the Get-CountDownTime function was clear screen between displaying the numbers. I debated whether to do that, but in the end decided to do so. The Comp
0 comments