Windows

How to Properly Pause a PowerShell Script

When I first learned about PowerShell, I immediately wanted to convert my batch files into PowerShell scripts and then enhance them with additional features. When I started that process, I quickly learned that PowerShell didn’t have anything equivalent to cmd.exe’s “Pause” command. I looked for a solution online and found the Microsoft TechNet article Windows PowerShell Tip: Press Any Key to Continue. This is the solution recommended by the article:

Write-Host "Press any key to continue ..."

$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

However, the above solution has two things wrong with it:

  • It doesn’t work from within Windows PowerShell ISE
  • Unlike cmd.exe’s “Pause” command, pressing keys like Ctrl and Alt causes the script to continue

To fix these two issues, I decided to write my own “Pause” function:

Function Pause ($Message = "Press any key to continue . . . ") {
	If ($psISE) {
		# The "ReadKey" functionality is not supported in Windows PowerShell ISE.

		$Shell = New-Object -ComObject "WScript.Shell"
		$Button = $Shell.Popup("Click OK to continue.", 0, "Script Paused", 0)

		Return
	}

	Write-Host -NoNewline $Message

	$Ignore =
		16,  # Shift (left or right)
		17,  # Ctrl (left or right)
		18,  # Alt (left or right)
		20,  # Caps lock
		91,  # Windows key (left)
		92,  # Windows key (right)
		93,  # Menu key
		144, # Num lock
		145, # Scroll lock
		166, # Back
		167, # Forward
		168, # Refresh
		169, # Stop
		170, # Search
		171, # Favorites
		172, # Start/Home
		173, # Mute
		174, # Volume Down
		175, # Volume Up
		176, # Next Track
		177, # Previous Track
		178, # Stop Media
		179, # Play
		180, # Mail
		181, # Select Media
		182, # Application 1
		183  # Application 2

	While ($KeyInfo.VirtualKeyCode -Eq $Null -Or $Ignore -Contains $KeyInfo.VirtualKeyCode) {
		$KeyInfo = $Host.UI.RawUI.ReadKey("NoEcho, IncludeKeyDown")
	}

	Write-Host
}

Here’s the minified version:

Function Pause($M="Press any key to continue . . . "){If($psISE){$S=New-Object -ComObject "WScript.Shell";$B=$S.Popup("Click OK to continue.",0,"Script Paused",0);Return};Write-Host -NoNewline $M;$I=16,17,18,20,91,92,93,144,145,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183;While($K.VirtualKeyCode -Eq $Null -Or $I -Contains $K.VirtualKeyCode){$K=$Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")};Write-Host}
Advertisements

Install PowerShell 2.0 on Windows XP Using a Batch File

I wrote a batch file (for use with Windows XP only) that installs PowerShell 2.0. Here are the three things you need to know about it:

  1. The batch file installs PowerShell 2.0 only if it is not already installed
  2. If service pack 3 for Windows is not installed, the batch file exits
  3. If .NET Framework 2.0 (at least service pack 1) is not installed, the batch file automatically installs the x86 version of .NET Framework 2.0 service pack 1

Here are the two files used by the batch file:

  1. Microsoft .NET Framework 2.0 Service Pack 1 (x86)
  2. Update for Windows XP (KB968930): includes Windows PowerShell 2.0 and Windows Remote Management (WinRM) 2.0

Here is the code for the batch file:

@ECHO OFF

REM Make sure this batch file is being run with Windows XP
VER | FINDSTR /L "5.1." > NUL
IF %ERRORLEVEL% NEQ 0 ECHO It appears that you're not using Windows XP, so this batch file will exit now.&GOTO EOF

REM See if PowerShell is installed
FOR /F "tokens=3" %%A IN ('REG QUERY "HKLM\SOFTWARE\Microsoft\PowerShell\1" /v Install ^| FIND "Install"') DO SET PowerShellInstalled=%%A
CLS

IF NOT "%PowerShellInstalled%"=="0x1" ECHO PowerShell doesn't appear to be installed.&GOTO CheckPrerequisites

REM PowerShell is installed, so now see which version it is
FOR /F "tokens=3" %%A IN ('REG QUERY "HKLM\SOFTWARE\Microsoft\PowerShell\1\PowerShellEngine" /v PowerShellVersion ^| FIND "PowerShellVersion"') DO SET PowerShellVersion=%%A
CLS

IF "%PowerShellVersion%"=="" (
 ECHO PowerShell appears to be installed, but the version number was unable to be
 ECHO determined.
 GOTO CheckPrerequisites
)

ECHO PowerShell %PowerShellVersion% appears to be installed.
IF %PowerShellVersion%==2.0 GOTO EOF

:CheckPrerequisites
ECHO.
ECHO Version 2 will now be installed.
ECHO.

REM Make sure service pack 3 for Windows is installed
REG QUERY "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion" /v CSDVersion | FIND "Service Pack 3" > NUL
IF %ERRORLEVEL% EQU 0 GOTO CheckNETFramework2SP
CLS

ECHO It appears that you're using Windows XP, but without service pack 3. Please
ECHO install service pack 3 and then run this batch file again.
ECHO.
GOTO EOF

:CheckNETFramework2SP
REM Service pack 3 for Windows is installed, so now make sure .NET Framework 2.0 (at least SP1) is installed
FOR /F "tokens=3" %%A IN ('REG QUERY "HKLM\SOFTWARE\Microsoft\NET Framework Setup\NDP\v2.0.50727" /v SP ^| FIND "SP"') DO SET NETFramework2SP=%%A
CLS

IF NOT "%NETFramework2SP%"=="" IF NOT "%NETFramework2SP%"=="0x0" GOTO InstallPowerShell2

ECHO Installing .NET Framework 2.0 SP1...
START "" /WAIT NetFx20SP1_x86.exe /q /norestart
ECHO.

:InstallPowerShell2
ECHO Installing PowerShell 2.0...
START "" /WAIT WindowsXP-KB968930-x86-ENG.exe /quiet /passive /norestart

:EOF

An Easy Way to Run PowerShell Scripts

According to the Microsoft TechNet article Running Windows PowerShell Scripts, these are the three ways to run a PowerShell script:

  1. From within PowerShell
  2. From a shortcut
  3. From the “Run” dialogue box

It turns out that, as of PowerShell 2.0, there is another way, which is to simply right-click the PowerShell script and choose “Run with PowerShell”. But what if you have several PowerShell scripts that you want to run in succession and not simultaneously? I ran into this problem, so I came up with a solution that involves a simple batch file. With this batch file, all you have to do to run one or more PowerShell scripts is drag it onto the batch file’s icon and let go. Here is the code for the batch file:

@ECHO OFF
CLS
IF NOT EXIST "%windir%\System32\WindowsPowerShell\v1.0\powershell.exe" GOTO NoPowerShell

IF NOT "%~1"=="" GOTO Start

ECHO Drag a PowerShell script (or multiple PowerShell scripts) onto this batch
ECHO file's icon and let go to run it.
ECHO.
PAUSE
GOTO EOF

:Start
REM Make sure the "%~1" parameter is a valid path
IF "%~1"=="" GOTO EOF
IF NOT EXIST "%~1" GOTO ShiftParameters

ECHO This batch file will now launch the following file using PowerShell:
ECHO.
ECHO %~1
ECHO.
ECHO *** BEGIN ***
"%windir%\System32\WindowsPowerShell\v1.0\powershell.exe" ^&\"%~1\"

REM If an error occurs, pause the batch file so that the user can review the error message
IF %ERRORLEVEL% EQU 1 PAUSE

ECHO *** END ***
ECHO.

:ShiftParameters
SHIFT
GOTO Start

:NoPowerShell
ECHO PowerShell wasn't found at the following location:
ECHO.
ECHO "%windir%\System32\WindowsPowerShell\v1.0\powershell.exe"
ECHO.
ECHO Please install PowerShell and try again.
ECHO.
PAUSE

:EOF

Use a Batch File to Detect Windows 2K, XP, 2003, Vista, or 7

A while ago I was in a situation where I needed to be able to detect the version of Windows that was being used to execute a batch file. After searching the Internet, the best script I found was this one by Rod of Rod.Net. I made some modifications to it and I came up with what I believe is the best script to use to detect which version of Windows is being used as long as it’s 2K, XP, 2003, Vista, or 7. Here’s the script:

@ECHO OFF
SET OSVersion=Unknown

VER | FINDSTR /L "5.0" > NUL
IF %ERRORLEVEL% EQU 0 SET OSVersion=2000

VER | FINDSTR /L "5.1." > NUL
IF %ERRORLEVEL% EQU 0 SET OSVersion=XP

VER | FINDSTR /L "5.2." > NUL
IF %ERRORLEVEL% EQU 0 SET OSVersion=2003

VER | FINDSTR /L "6.0." > NUL
IF %ERRORLEVEL% EQU 0 SET OSVersion=Vista

VER | FINDSTR /L "6.1." > NUL
IF %ERRORLEVEL% EQU 0 SET OSVersion=7

IF %OSVersion%==Unknown (
 ECHO Unable to determine your version of Windows.
) ELSE (
 ECHO You appear to be using Windows %OSVersion%
)

ECHO.
PAUSE

Quickly Find a Windows Computer’s Sysprep Identification String

At work, I’m in a situation where we have over 1,000 computers to manage. Over the years, we’ve gone through several different versions of a base image of Windows XP created with Sysprep which we put on all of the new computers that come in. When we’re out in the field troubleshooting a problem on a computer, it’s nice to know which image was used on that computer. Previously, I was having to open regedit and navigate to HKEY_LOCAL_MACHINE\SYSTEM\Setup\OemDuplicatorString. This got old real fast, so I wrote a quick VBScript to display it:

Const HKEY_LOCAL_MACHINE = &H80000002

strComputer = "."
Set objRegistry = GetObject("winmgmts:\\" & strComputer & "\root\default:StdRegProv")

strKeyPath = "SYSTEM\Setup"
strValueName = "OEMDuplicatorString"
objRegistry.GetMultiStringValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,arrValues

If IsNull(arrValues) Then
	Wscript.Echo "This computer has no Sysprep identification string."
Else
	Wscript.Echo "This computer's Sysprep identification string is:" & VbCr & VbCr & arrValues(0)
End If

Simply save that code as “Display Sysprep Identification String.vbs”! For an extremely detailed guide on how to use Sysprep, I recommend this one.