Advanced Windows PowerShell Scripting Video Training

Advanced Windows PowerShell Scripting Video Training
Advanced Windows PowerShell Scripting Video Training

Wednesday, September 30, 2009

Delegwiz.inf templates from Microsoft

The Delegwiz.inf file is a text document the add additional tasks that can be delegated in the Delegation Control Wizard in Windows Server 2008. Microsoft publishes additional templates that you can add to this file to expand the capability of the Delegation of Control Wizard. Below is a link to the updated Delegwiz template file from Microsoft.

Simple replace the text in the Delegwiz.inf file with the template information in the article from the link above.

Tuesday, September 29, 2009

Calculating Your System Uptime in PowerShell

Today’s PowerShell lesson is on how to determine your system uptime. I know, not very sexy. It will introduce us to some date/time math though.

Before we begin, I just want to clearify the text formatting that I'm using:

This means it is something that I typed.

This is the resulting output.

When We get to the actual scripts, I'll color code the comments out so you can focus on the code.

The first thing that I want to do is discover how to get the current date and time from my client in PowerShell.


Friday, September 04, 2009 3:05:43 PM

Easy enough. You can see that Windows will format the output as DayOfWeek, Month Day, Year Hour:Minute:Second Am/PM. OK, so we know what time it is now. But when did your computer turn on last? We are going to pull this information from the WMI class of Win32_Operating System. Let’s take a look at the properties of this class.

Gwmi Win32_OperatingSystem | gm

In the above command, GWIM is an alias for Get-WmiObject and GM is an alias for Get-Member. Don’t believe me? Try these commands.

Get-Alias | Where{$_.Definition -eq "Get-WmiObject"} | FL

Name : gwmi

CommandType : Alias

Definition : Get-WmiObject

ReferencedCommand : Get-WmiObject

ResolvedCommand : Get-WmiObject

Get-Alias | Where{$_.Definition -eq "Get-Member"} | FL

Name : gm

CommandType : Alias

Definition : Get-Member

ReferencedCommand : Get-Member

ResolvedCommand : Get-Member

OK, back to the task at hand. Execute the command below

gwmi Win32_OperatingSYstem | gm -membertype property

TypeName: System.Management.ManagementObject#root\cimv2\Win32_OperatingSystem

Name MemberType Definition

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

BootDevice Property System.String BootDevice {get;set;}

BuildNumber Property System.String BuildNumber {get;set;}

BuildType Property System.String BuildType {get;set;}

Caption Property System.String Caption {get;set;}

CodeSet Property System.String CodeSet {get;set;}

CountryCode Property System.String CountryCode {get;set;}

CreationClassName Property System.String CreationClassName {get;set;}

CSCreationClassName Property System.String CSCreationClassName {get;set;}

CSDVersion Property System.String CSDVersion {get;set;}

CSName Property System.String CSName {get;set;}

CurrentTimeZone Property System.Int16 CurrentTimeZone {get;set;}

DataExecutionPrevention_32BitApplications Property System.Boolean DataExecutionPrevention_32BitApplications {get;set;}

DataExecutionPrevention_Available Property System.Boolean DataExecutionPrevention_Available {get;set;}

DataExecutionPrevention_Drivers Property System.Boolean DataExecutionPrevention_Drivers {get;set;}

DataExecutionPrevention_SupportPolicy Property System.Byte DataExecutionPrevention_SupportPolicy {get;set;}

Debug Property System.Boolean Debug {get;set;}

Description Property System.String Description {get;set;}

Distributed Property System.Boolean Distributed {get;set;}

EncryptionLevel Property System.UInt32 EncryptionLevel {get;set;}

ForegroundApplicationBoost Property System.Byte ForegroundApplicationBoost {get;set;}

FreePhysicalMemory Property System.UInt64 FreePhysicalMemory {get;set;}

FreeSpaceInPagingFiles Property System.UInt64 FreeSpaceInPagingFiles {get;set;}

FreeVirtualMemory Property System.UInt64 FreeVirtualMemory {get;set;}

InstallDate Property System.String InstallDate {get;set;}

LargeSystemCache Property System.UInt32 LargeSystemCache {get;set;}

LastBootUpTime Property System.String LastBootUpTime {get;set;}

LocalDateTime Property System.String LocalDateTime {get;set;}

Locale Property System.String Locale {get;set;}

Manufacturer Property System.String Manufacturer {get;set;}

MaxNumberOfProcesses Property System.UInt32 MaxNumberOfProcesses {get;set;}

MaxProcessMemorySize Property System.UInt64 MaxProcessMemorySize {get;set;}

MUILanguages Property System.String[] MUILanguages {get;set;}

Name Property System.String Name {get;set;}

NumberOfLicensedUsers Property System.UInt32 NumberOfLicensedUsers {get;set;}

NumberOfProcesses Property System.UInt32 NumberOfProcesses {get;set;}

NumberOfUsers Property System.UInt32 NumberOfUsers {get;set;}

OperatingSystemSKU Property System.UInt32 OperatingSystemSKU {get;set;}

Organization Property System.String Organization {get;set;}

OSArchitecture Property System.String OSArchitecture {get;set;}

OSLanguage Property System.UInt32 OSLanguage {get;set;}

OSProductSuite Property System.UInt32 OSProductSuite {get;set;}

OSType Property System.UInt16 OSType {get;set;}

OtherTypeDescription Property System.String OtherTypeDescription {get;set;}

PAEEnabled Property System.Boolean PAEEnabled {get;set;}

PlusProductID Property System.String PlusProductID {get;set;}

PlusVersionNumber Property System.String PlusVersionNumber {get;set;}

Primary Property System.Boolean Primary {get;set;}

ProductType Property System.UInt32 ProductType {get;set;}

QuantumLength Property System.Byte QuantumLength {get;set;}

QuantumType Property System.Byte QuantumType {get;set;}

RegisteredUser Property System.String RegisteredUser {get;set;}

SerialNumber Property System.String SerialNumber {get;set;}

ServicePackMajorVersion Property System.UInt16 ServicePackMajorVersion {get;set;}

ServicePackMinorVersion Property System.UInt16 ServicePackMinorVersion {get;set;}

SizeStoredInPagingFiles Property System.UInt64 SizeStoredInPagingFiles {get;set;}

Status Property System.String Status {get;set;}

SuiteMask Property System.UInt32 SuiteMask {get;set;}

SystemDevice Property System.String SystemDevice {get;set;}

SystemDirectory Property System.String SystemDirectory {get;set;}

SystemDrive Property System.String SystemDrive {get;set;}

TotalSwapSpaceSize Property System.UInt64 TotalSwapSpaceSize {get;set;}

TotalVirtualMemorySize Property System.UInt64 TotalVirtualMemorySize {get;set;}

TotalVisibleMemorySize Property System.UInt64 TotalVisibleMemorySize {get;set;}

Version Property System.String Version {get;set;}

WindowsDirectory Property System.String WindowsDirectory {get;set;}

__CLASS Property System.String __CLASS {get;set;}

__DERIVATION Property System.String[] __DERIVATION {get;set;}

__DYNASTY Property System.String __DYNASTY {get;set;}

__GENUS Property System.Int32 __GENUS {get;set;}

__NAMESPACE Property System.String __NAMESPACE {get;set;}

__PATH Property System.String __PATH {get;set;}

__PROPERTY_COUNT Property System.Int32 __PROPERTY_COUNT {get;set;}

__RELPATH Property System.String __RELPATH {get;set;}

__SERVER Property System.String __SERVER {get;set;}

__SUPERCLASS Property System.String __SUPERCLASS {get;set;}

Not very pretty is it. We are interested in the property LastBootUpTime. Let’s take a closer look at this property. First off, create a variable to hol this object

$osBootTime=Get-WmiObject win32_operatingSystem

Now type:



Yes, this is actually how Windows reads date/time information. We need to make this more user friendly. Try this command to make things look a bit nicer


Friday, September 04, 2009 11:24:52 AM

OK, now we need to figure out the time difference between the current date/time and the string of text that was returned from the previous command. Now it is time for things to get interesting. We will use the Subtract method that is part of each System.DateTime object. Let’s take a look at the code.

For those of you who know me, I like to keep my Main code as simple as possible. That means we are going to be creating a lot of functions and just using the main script code for traffic control. Anything in green are comments.

  1. # ======================================
  2. # Script Name: SystemUptime.PS1
  3. # Storage Path: D:\PowerShell\
  4. # Author: Jason A.Yoder, MCT
  5. # Company: MCTExpert, Inc.
  6. # Website:
  7. # Blog:
  8. # Version: 1.0
  9. # Created: September 4, 2009
  10. # Purpose: To be able to calculate the
  11. # current system uptime.
  12. # ======================================
  13. # ======================================
  14. # Variables
  15. # --------------------------------------
  16. # Set debug level to strict
  17. Set-PSDebug -strict
  18. # Name: $Current_Time
  19. # Purpose: Holds the current Date and
  20. # time information from the
  21. # local client.
  22. $Current_Time
  23. # Name: $strOSBootTime
  24. # Purpose: Holds the string value of the
  25. # boot time for the operating
  26. # operating system.
  27. $strOSBootTime = ""
  28. # Name: $UpTime
  29. # Purpose: Object holds the Date/Time
  30. # difference information
  31. $UpTime = ""
  32. # ======================================
  33. # ======================================
  34. # Version History
  35. # --------------------------------------
  36. # Version:
  37. # Date:
  38. # Reason:
  39. # ======================================
  40. # ======================================
  41. # Functions
  42. # --------------------------------------
  43. #
  44. Function Get-CurrentDateTime
  45. {
  46. # Function: Get-CurrentDateTime
  47. # Arguments: None
  48. # Purpose: Returns the current DateTime
  49. # object to the variable
  50. # $Current_Time
  51. $Current_Time = Get-Date
  52. }
  53. # --------------------------------------
  54. Function Get-BootString
  55. {
  56. # Function: GetBootString
  57. # Arguments: None
  58. # Purpose: Returns a string of the
  59. # Date/Time the local computer
  60. # was booted on.
  61. # --------------------------------------
  62. $strOSBootTime=Get-WmiObject win32_operatingSystem
  63. $Script:strOSBootTime=[Management.ManagementDateTimeConverter]::ToDateTime($strOSBootTime.LastBootUpTime)
  64. }
  65. # --------------------------------------
  66. Function Show-Uptime
  67. {
  68. # Function: Show-Uptime
  69. # Arguments:
  70. # - $Current : The current system time.
  71. # - $Boot : The boot time.
  72. # Purpose:
  73. # --------------------------------------
  74. $Script:UpTime = $Current_Time.subtract($strOSBootTime)
  75. }
  76. # --------------------------------------
  77. Function Show-Data
  78. {
  79. # Function: Show-Data
  80. # Arguments: None
  81. # Purpose: Displays the information
  82. # stored in object $UpTime
  83. # in a user friendly way.
  84. # --------------------------------------
  85. Write-Host "Your System has been up for:"
  86. Write-Host $UpTime.Days + " Days"
  87. Write-Host $UpTime.Hours + " Hours"
  88. Write-Host $UpTime.Minutes + " Minutes"
  89. Write-Host $UpTime.Seconds + " Seconds"
  90. }
  91. # ======================================
  92. # End of Functions
  93. # ======================================
  94. # ======================================
  95. # Script Body
  96. # --------------------------------------
  97. Get-CurrentDateTime(0)
  98. Get-BootString(0)
  99. Show-Uptime(0)
  100. Show-Data(0)
  101. # ======================================
  102. # Script Body
  103. # ======================================
  104. Get-CurrentDateTime(0)
  105. Get-BootString(0)
  106. Show-Uptime(0)
  107. Show-Data(0)
  108. # ======================================
  109. # End of Script Body
  110. # ======================================

· Lines 1 – 12

o Just my header information.

· Lines 14-37

o This is where I’m declaring my variables up front.

o The command Set-PSDebug –Strict I like using the VBScript command of Option Explicit.

· Lines 40-46

o This section is used to keep track of versions and changes.

· Lines 55-65

o In this function, we are simply settings the current DateTime object into a variable.

· Lines 70-82

o We are calling the boot time of the system and placing it into a variable

o We are also converting it into a usable format.

· Lines 87-98

o Here is were the difference between the dates and time are calculated.

· Lines 102-116

o This functions displays the data in a user friendly way.

· Lines 125-135

o This is the main script body.

Did I need to write so much code to do this? No I did not. I wrote this code in a way to help others understand what I did and to also remind myself in the future how I did it. Below is the code in the shortest format that I know how to write it in.

$Current_Time = Get-Date

$strOSBootTime=Get-WmiObject win32_operatingSystem


$Script:UpTime = $Current_Time.subtract($strOSBootTime)

Write-Host "Your System has been up for:"

Write-Host $UpTime.Days + " Days"

Write-Host $UpTime.Hours + " Hours"

Write-Host $UpTime.Minutes + " Minutes"

Write-Host $UpTime.Seconds + " Seconds"

Monday, September 28, 2009

What is a SAMID?

The SAMID is an attribute is the Security Account Manager name for user accounts and security descriptors. The Security Account Manager stores user passwords. If a user account and password are entered that match a pair in the database, the user is logged into the system.


Wednesday, September 23, 2009

Is there a tool for determining a users effective permissions through a network a share?

Determining a users effective permission is a very challenging task. Below are some conditions that could effect the effective permissions a user experiences:

  • Anonymous Logon
  • Batch, Creator Group
  • Dialup
  • Enterprise Domain Controllers
  • Interactive
  • Network
  • Proxy
  • Restricted
  • Remote
  • Service
  • System
  • Terminal Server User
  • Other Organization
  • This Organization

Further still is accessing the data through a share. This is the problem. After some searching, I have not been able to find a tool that determines the users effective permission when taking network share access into account. The formula that is generally used for a manual determination is:

· Determine the effective NTFS permission level.

· Determine the effective Share permission level.

· The most restrictive between the two is the effective permission.

A useful tool would have to ask under what conditions is the user connecting? From the list above, there are many potential answers.

Tuesday, September 22, 2009

What loop to use in PowerShell?

PowerShell allows you to control the flow of your scripts through several different looping options. Below are some examples of what types of loops to use.

For loop:

  • Controls execution of code while a condition is true.
  • Usually used to perform a action a certain number of times.


For ($i = 1; $i –le 10; $i++) {Write-Host “Loop index is at $i”}


  • Runs while a condition is true.



while($Val -ne 3)



Write-Host $val


Do While

  • Evaluates a condition before running code.
  • If the condition is false, the code will not run.


$Index = 10

Do {$index--

Write-Host "$Index"

} while ($Index -gt 0)

Do Until

  • Evaluates the condition after the code has run once.
  • Loops through the code until a condition becomes true.
  • Ensures that the code will be run at least once before the loop terminates.


$Str = "My Text String"

do {

$str = $str.remove($str.length - 1)

write-host $str

} until ($str.length -lt 3)

Monday, September 21, 2009

What is the syntax for adding users to a group with DSMOD?

Utilizing DSMOD to add users to a group requires that you be careful when typing the distinguished name of both the user and the group. Below is an example of a group named ITDept. This group is in the OU of Departments in the domain You want to add two users with the CN of Mike and Jill. Here is the syntax:

DSMOD Group “cn=ITDept,ou=Departments,dc=wilderness,dc=com” –addmbr “cn=Mike, ou=Departments,dc=wilderness,dc=com” “cn=Jill, ou=Departments,dc=wilderness,dc=com”

The list of distinguished names that you are adding is space delimited.


Tuesday, September 15, 2009

Change Server Core Name

Objective: Change the name of a Server Core Machine:

Task 1: Get the name of the machine:
• At the command prompt, type hostname
• Record the name of the computer: ________________________

Task 2: Change the name of the computer
• Type netdom RenameComputer Old-Name /NewName:New-Name
• Press Enter.
• Restart the computer by typing Shutdown /r /t 0
o The Shutdown command allows you to shutdown a computer. The following switches are used:
- /r - Shutdown and restart the computer
- /t xxx - Sets a wait period in seconds before shutting down the computer.

Task 3: Verify the name change
• Log into the server
• Type hostname and verify the computer has changed its name.

How can I parse a string of text in PowerShell?

For you vbscripters out we had a built in function call split that allowed us to split text strings into an array. We have the same functionality as method in PowerShell.

First create a variable:
  • $Var1="“10,15,20,9,8,7”"

Now let's discover the methods that are available to this variable. Powershell is smart enough to know that this variable is a string.
  • $Var1 | Get-Member

Noticed that Split is a method. Let’s go ahead and execute this method.

The “,” tells PowersShell that our delimiter is going to be the comma. You can choose any character to be your delimiter.

You can also treat these as cells in an array.

• $Var2 = $Var1.Split(“,”)
• $Var2[1]

After you execute the second command, the contents of cell 1 in the array $Var2 will be displayed. In this case, it should be 15.

Sunday, September 13, 2009

Can users place data in their local My Documents folder after redirection?

Once file redirection is configured and working, users will still be able to get to their My Documents folders as if it were still on their local computer. If you click Start and right mouse click My Documents àProperties, you will see that the My Documents is now located on remote storage. If users browse C:\Documents and Settings\username they will no longer see a My Documents folder.

File redirect is a useful way to ensure that your organizations data is always on a redundant, backed up storage device. Also consider implementing file storage quotas to ensure that a few users do not consume all of your storage space.

Folder Redirection:

Storage Quota:

Tuesday, September 8, 2009

Do user computers need the admin pack if they are group managers?

If you would like your users to be able to add and remove users from the groups they manage, then yes. You will need to install the ADMINPAK.MSI from the server c:\Windows\System32. You will also need to enable the management in the group properties themselves. On the Managed By tab, you need to click Change and then select the user. You also need to check Manager can update membership list. It would also be a good practice to create a custom task pad that will allow them to only add and remove user accounts from there group. This ability should only be for users in the OU that contains the group.

Rebooting Clients with PowerShell Part 2 of 2

Last Tuesday, we looked at how to reboot/shutdown/logoff remote clients in powershell. We also looked the GPO settings to allow you to do this to any client. Now, we are going to allow you to do this to multiple clients all at once.

First off, the original objective of this post was to recreate a script that I used in VBScript to reboot my servers during the wee morning hours so I would not have to get out of bed. So, before proceeding any further, please create a service account with appropriate rights. In 2008, there is an OU called Managed Service Accounts. Why not place it there.

OK, here are our tasks:
• Create a text file containing the names of the clients that we want to reboot.
• Create a script that reads each file and reboots the correct client.
• Create a scheduled task for you to designate when this should happen.

Task 1: Create a text file containing the names of the clients that we want to reboot.
This is a simple one. Just create a text file and put one client name per line. Save it in a location that the service account has access to. By using this text file, you will be able to easily add and remove client names.

Task 2: Create a script that reads each file and reboots the correct client.
# ======================================
# Script Name:
# Author: Jason A.Yoder, MCT
# Company: MCTExpert, Inc.
# Website:
# Blog:
# Version: 1.0
# Created: Aug. 9, 2009
# Purpose: This script is designed to allow
# Network Administrators the ability
# too schedule the rebooting of any of
# their client.
# ======================================

# ======================================
# Script Body
# --------------------------------------

#Load the list of clients.
$ClientList = gc c:\ClientList.txt

# Cycle through each name on the list and Force Reboot
# that client.
ForEach ($Comp in $ClientList)
$CompObj = gwmi Win32_OperatingSystem –computer $Comp

# ======================================
# End of Script Body
# ======================================

In the above script, we are assuming that the text file containing the names of the clients to reboot is contained at c:\ClientList.txt. We use the Get-Content, or GC, cmdlet to read the contents into the variable $ClientList. From there we use the ForEach loop to cycle through each client and reboot it. You should recognize the two lines of code from part I of this article.

Task 3: Create a scheduled task for you to designate when this should happen.
PowerShell has some built in security. If you double click on a .PS1 file (PowerShell script), it just opens in Notepad. That is by design. You can execute a command line to run the script without opening the PowerShell Shell.

The command to do this is: PowerShell.exe FilePath\Filename.ps1

The problem here is that you need to run the Set-ExecutionPolicy command from inside of PowerShell to allow scripts to run. Running this command will only error out:
File ----- cannot be loaded because the execution of scripts is disabled on
This system. Please see “get-help about_signing” for more details.”

To fix this problem, you need to set the execution policy in Group Policy.
• Open Group Policy Editor.
• Create or edit the policy that will control the client that the script is running on.
• Expand: Computer Configuration --> Policies --> Administrative Templates --> Windows Powershell.
• Open Turn on Script Execution.
• Select Enabled
• From the drop down box, select Allow local scripts and remote signed scripts.
• Click OK.
• Close Group Policy Management Editor.
• Make sure you refresh the policy on the computer that the script will run on.

Now that we have set the Execution Policy, we can create the scheduled task.

• Click Start.
• Right Click Computer and select Manage.
• Click Configuration --> Task Schedular.
• Click Create Task from the Actions pane.
• Provide a name and description for this task. Remember, you want other people who may look at your work to be able to understand it.
• Click Change User or Group.
• Provide the credentials for your service account.
• Click the Triggers tab.
• Click New.
• Select One Time for the frequency.
• Give it the date and time you want this task to run. Remember, this is a forced reboot. Make sure you are not interfering with work or backups.
• Click Actions tab.
• Click New.
• Click Start a program and click Next.
• In the Program/Script field type powershell.exe FilePath\FileName.ps1.
• Click OK.
• If you are prompted about running a program with arguments, click Yes.
• Click OK

From here on out, each time you need to use the task, just edit the trigger for the date and time that you want. A lot of work, but we learned many key activities in both part I and part II

• How to create an instance of a WMI Object.
• How to enumerate the methods and properties of an object.
• The different shutdown parameters available in Win32_OperatingSystem.Win32Shutdown.
• How to open PowerShell with administrative credentials.
• How to manually allow PowerShell to execute scripts on remote computers.
• How to configure PowerShell to execute scripts on remote computers via Group Policy.
• The PowerShell cmdlets that let us read text files into our scripts.
• How to execute a PowerShell script without having to open PowerShell.
• How to set the Execution Policy through Group Policy.
• How to create a Scheduled Task.

By the way, That VB script had 58 lines of code in the main code, and 1 function with 25 lines of code. We did this in 6 lines of code with no functions. Can you see any advantages to PowerShell now?

Sunday, September 6, 2009

Renaming User Accounts in Active Directory with VBScript

This one proved to be a little more difficult then I first thought. We were able to get a few attributes to change, but in further testing; I found that AD was throwing a fit. The problem was resolved using the ADSI Editor Snap-in. What I did was watch each value and whether or not the correct value was reflected in the User accounts properties. The following code relies on a text file containing the old and new user names formatted as such:


You can modify the code to import the usernames anyway that works for you. Also, do not forget to change the variables ParentDN and strUPNSuffix to match your environments.

' ================================
' RenameUSerAccounts.vbs
' Author: Jason A. Yoder, MCT
' Date: May 15, 2009
' Required Files:
' - A Text file named "names.txt". In this script, the file
' location is hard coded.
' The format for the text file is %OldUserName%,%NewUserName%
' Other Information:
' - The interesting part of this code is in the Do While...Loop.
' It does not matter how you get the data into the script
' as long as you have the ParentDN and both old and new usernames.
' ================================

Const ForReading = 1
ParentDN = "OU=HR,DC=FourthCoffe,DC=com" ' Change this line to reflect your environment.
strUPNSuffix = "" ' Change this line to reflect your environment.

' Read in the data file of old and new user names.
Set objFilesys = CreateObject("Scripting.FileSystemObject")
Set objFileText = objFileSys.OpenTextFile("C:\Users\Administrator\Desktop\Test\Names.txt", ForReading, true)

Do Until objFileText.AtEndOfStream '
strText = objFileText.Readline ' Reads the Names.txt file one line at a time.
aryText = Split(strText,",") ' Slipts each value into different cells of aryText.

strUserOldName = aryText(0)
strUserNewName = aryText(1)

set objCont = GetObject("LDAP://" & ParentDN)
objCont.MoveHere "LDAP://cn=" & strUserOldName & "," & ParentDN, "cn=" & strUserNewName
set objUser = GetObject("LDAP://cn=" & strUserNewName & "," & ParentDN)

objUser.Put "sAMAccountName",strUserNewName
objUser.Put "userPrincipalName",strUserNewName & "@" & strUPNSuffix
objUser.Put "GivenName",strUserNewName
objUser.Put "DisplayName",strUserNewName


WScript.Echo "Done"

Tuesday, September 1, 2009

How to create a Windows PE disk.

Windows PE is a pre-execution environment for the Windows platform. Anybody who has used the Vista/2008 recovery option has used Windows PE. The instructions below will guide you through creating a windows PE disk. It is command line driven.

In class, we talked about using Windows PE and Imagex.exe to reimage your clients. This will allow you to restore a client to the same state that it was in prior to release to the user. When you create you WinPE image, do not forget to add the Imagex.exe command from the Windows Automated Installation Kit (WAIK). Imagex is what allows you to capture and apply images.

The process for rebuilding the client is:

1) Offload the client data using User State Migration Tool (USMT) to an external drive.

2) Boot the client in Windows PE.

3) Format the hard drive.

4) Apply the image (imagex /apply ImageSource ImageNumber Imagedetination)

a. Ex imagex /apply e:\ClientImages\Client013.wim 1 c:

5) Run updates.

6) Restore the user data with USMT

7) Rejoin to the domain if needed.

8) Verify the restoration is successful.

9) (Optional) Boot into Windows PE and create a new image. If update process took a considerable amount of time, consider creating a new image to reduce the wait the next time around.

Your organizations policy needs to support this process. You will be only restore the computer to a state that allows the user to do their job. If the user had any personal software installed, it will not be there after the re-imaging process.

Create a Windows PE disk/drive (Hard disk) (CD-ROM)

User State Migration Tool

Windows Automated Installation Kit (Where you get imageX from)

Rebooting Clients with PowerShell Part I of 2

This week’s PowerShell tip is actual inspired by one of the most useful VBScripts that I have ever used in managing a network. Let’s just call it a massive system reboot. Remember way back when…. When you had to physically visit each of your servers for updates. For me, it turned into a two week trip every 3 months. It was way cool at first. Especially for trips to California (I live in Indiana. Anything outside the Midwest is cool.) This started turning into both a time and budget drain. In Windows 2000, we had the ability to remote desktop in. Now, I was working two 12 hour days, 4 weekends a year. The problem was the reboot. I had to reboot the servers. I would mostly just work on other things while the servers were updating and then reboot when necessary. Of course there was the occasional shut down. Then I would have to call someone on site to drive into work on a weekend to press the power button.

Once I started using a script to reboot servers for me, my weekend time went to zero. Also, the accidental shut downs were non-existent. That same VBScript still works on Server 2008. But this is the age of PowerShell. So I took this opportunity to rewrite the script in PowerShell. Let’s take a look at some of the key parts.

We are going to use the WMI object of W32_OperatingSystem. Let’s enumerate the methods in
W32_OperatingSystem in PowerShell.

This first step creates an instance of the W32_OperatingSystem object and places it in a variable called $WinShut.

• $WinShut = Get-WmiObject win32_OperatingSystem

We are now going to enumerate the methods that are available to us. Remember, methods are actions, properties are data.

• $WinShut | Get-Member –membertype method

TypeName: System.Management.ManagementObject#root\cimv2\Win32_OperatingSystem

Name MemberType Definition
---- ---------- ----------
Reboot Method System.Management.ManagementBaseObject Reboot()
SetDateTime Method System.Management.ManagementBaseObject
Shutdown Method System.Management.ManagementBaseObject Shutdown()
Win32Shutdown Method System.Management.ManagementBaseObject Win32ShutdownTracker

You should have gotten output similar to what is above. We are interested in Win32Shutdown.

Win32Shutdown has different values that we can assign to it:
• 0 - Log Off
• 4 - Forced Log Off
• 1 - Shutdown
• 5 - Forced Shutdown
• 2 - Reboot
• 6 - Forced Reboot
• 8 - Power Off
• 12 - Forced Power Off

Let’s give it a try. We can do this from scratch or use the variable that we created earlier. Just to warn you, DON’T DO THIS ON THE COMPUTER YOU ARE READING THIS BLOG ON. Do it on a test machine.

• $WinShut.Win32Shutdown(0)

What about a remote logoff or shutdown?

We need to open PowerShell with an account that has administrative credentials.
• Click Start and type CMD.
• Press Enter.
• Type runas /env /user:administrator@domain.local “powershell.exe”

Of course replace administrator@domain.local with the UPN of an account with administrative rights.

PowerShell v2 has some nice remote features built into it. But first, let’s prep your Windows Server 2008 R2 and Windows 7 machines.

• Click Start --> Control Panel
• Click System and Security
• Click Allow a program through Windows Firewall.
• Check:
o File and Printer Sharing
o Windows Management Instrumentation(WMI)
• Click OK

This is good for one or two computers. What about 500? This is when Group Policy comes into play.

• Open Group Policy Management
• Open or create a Group Policy to manage your firewall on the clients that you are going to run this script against.
• Click Computer Configuration --> Policies --> Windows Settings --> Windows Firewall with Advanced Security --> Inbound Rules.
• Right Click Inbound Rules and Click New Rule.
• Click Predefined.
• In the Drop down box click File and Printer Sharing
• Click Next
• Click Next
• Click Finish
• Create a new rule for Windows Management Instrumentation(WMI) also.

Remember that the policy must refresh on the clients before you can proceed.

OK, now let’s connect with our clients and log them off.

• $WinShut = gwmi Win32_OperatingSystem –computer computername.

In this line, we used the alias gwmi to shorten the typing. Gwmi is short for Get-WMIObject. Replace computername with the name of the client that you want to reboot


Once you press enter, the client will reboot. Again, replace the parameter of 6 with the desired outcome.

Next Tuesday, we will look at how to restart multiple clients in Part II of this article.