Advanced Windows PowerShell Scripting Video Training

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

Friday, April 29, 2011

Remove Adobe Flash Player Cookies

Here is a new worry for you and your users.  Adobe Flash creates cookies that are deleted through traditional methods.  In researching this tasty little dessert, I found reports that suggest that these super cookies can be use to restore traditional cookies that you deleted.  Other reports suggest that half of the internet's websites use this form of cookie.  OK, so how do you get ride of them?
Open the link below in a new browser:


Click Delete all sites.

Next click the tab the is marked below:
Drag the slider bar so it says "None” and check Never Ask Again.

This will prevent new cookies from being written.

Thursday, April 28, 2011

Enumerate Members of local groups in PowerShell

Here is another script from my last PowerShell class.  After we took a look at the script to enumerate the users who had User Rights assigned to them on a server, one the delegates in class asked if it was possible to enumerate the local users in local groups.  I had to resort to some PowerShell V1 tactics, but it works.  I also got a little help from Steve Schofield’s blog.

Script Name: LocalGroups.ps1
Author: Jason A. Yoder, MCT
Script Purpose:
Enumerate the local user accounts that are members
of local groups

$GroupList : Holds the names of all the groups on the

$StrComputer : Used to store the name of the client to
               run this script on.  The "." means the
               local client.

$GL : Used to help cycle through the collection
      $Group List.
$Members : A collections of all the members of a group.              
# =========================================================
# Main Code:
Set-StrictMode -version 2.0

# Enumerate the local groups on the client.
$GroupList = Get-WmiObject Win32_Group | ForEach {$}
$strComputer = "."

# Cycle through each group and enumerate the
# Group members.
ForEach ($GL in $GroupList)
    $computer = [ADSI]("WinNT://" + $strComputer + `
    $Group = $computer.psbase.children.find($GL)
    $members= $Group.psbase.invoke("Members") |
    %{$_.GetType().InvokeMember("Name", 'GetProperty', `
    $null, $_, $null)}

    # Display the group and its members.
    Write-Host "Group Name: $GL"
    ForEach($user in $members){Write-Host $user}
    Write-Host "------------------------------------------"
# == End of Main Code =====================================

Wednesday, April 27, 2011

View the NIC configuration of a VM in Virtual Machine Manager

System Center Virtual Machine Manager as a neat little graphical way of viewing the NIC configuration of a VM to see which physical NIC, or virtual network the VM is connected to.

In Virtual Machine Manager, right click the VM you are interested in.

Click View Networking.

You will get a window similar to the one below.

This particular VM has its NIC connected to a virtual network called MCT Network.

Tuesday, April 26, 2011

PowerShell Script to replace items in a text file

This script is a product of one my PowerShell classes in March 2011.  The problem was presented by a learner in the class.  His task was to take a large text file that needed to be parsed for question marks and have them replaced with spaces.  We expanded the script to make it more portable and useful in more situations.

As with all my PowerShell classes, I encourage the participants to have a project in mind when they arrive.  With a project in hand, the light bulb in the participants head turns on as they learn more and more skills to make their project a success.

<# ========================================================
Script: Replace.ps1
The input parameters are the input file, the new output
file.  We also needed to provide what we wanted to replace
with what.  Adding these extra parameters made the script
more portable.
Param (
    $InFile = $(Read-Host 'Input File:
    $OutFile = $(Read-Host 'Output File:
    $ReplaceWhat = $(Read-Host 'Replace what:
    $ReplaceWith = $(Read-Host 'Replace With:
After testing reviled that the question mark needed
an escape character, we added this switch statement
for some of the special characters used in Regular
Switch ($ReplaceWhat){
    "^" {$ReplaceWhat = "\$ReplaceWhat"; Break
    "$" {$ReplaceWhat = "\$ReplaceWhat"; Break
    "*" {$ReplaceWhat = "\$ReplaceWhat"; Break
    "?" {$ReplaceWhat = "\$ReplaceWhat"; Break
    "\" {$ReplaceWhat = "\$ReplaceWhat"; Break
    "." {$ReplaceWhat = "\$ReplaceWhat"; Break
The code below first grabs the content of the input file.
It then pipes that content to a ForEach loop that issues
a replace command between the contents of the $ReplaceWhat
with the $ReplaceWith variables.

(Get-Content $InFile
) |
    ForEach {$_ -replace $ReplaceWhat, $ReplaceWith
} |
   Add-Content $OutFile

"Script: Replace.ps1 - Completed"

Monday, April 25, 2011

Use Group Policy to populate IE Favorites

Using Group Policy to populate the favorites in Internet Explorer allows you to make sure your users have quick access to mission critical websites.  To do this, create or use an existing GPO that is properly scoped to the users you want to publish the links to.

In Group Policy Manager right click the GPO and click Edit.

Expand User Configuration / Policies \ Windows Settings / Internet Explorer Maintenance / URLs

Double click Favorites and Links


Click Add URL

Provide a name and a URL.  You can even provide the location for a custom icon for the site.

Click OK.


Once you are finished, click OK in the Favorites and Links window.

Close the Group Policy Management Editor to save the policy.

Refresh the Group Polices on a client and test.

Should the user delete this link, it will re-appear at the next Group Policy refresh.

Friday, April 22, 2011

How to prevent users from opening PowerShell in a different Execution Policy than you require.

Users have the ability to open PowerShell with any Execution Policy level that they want.  The idea behind the Execution Policy is to prevent unintentional execution of scripts.  Your users do this by typing at a command line:

PowerShell –ExecutionPolicy PolicyLevel

The PolicyLevel is the desired Execution Policy.  Through Social Engineering, an attacker could instruct a user how to execute their malicious scripts by using the above method of the Set-ExecutionPolicy cmdlet.

You can prevent this by using Group Policy. I created a GPO with the sole purpose of setting the PowerShell Execution Policy to AllSigned.  This setting is located at Computer Configuration \ Policies \ Administrative Templates \ Windows Components \ Windows PowerShell \ Turn on Script Execution. 

I applied the policy and verified that the client’s default execution policy was set to AllSigned by opening PowerShell using the GUI.

I then closed PowerShell and then opened it again.  This time by using the following command line:

PowerShell –ExecutionPolicy Unrestricted

I was able to confirm that my Group Policy prevented my user from changing the Execution Policy.

When I used the Set-ExecutionPolicy Unrestricted command and also confirmed the change, I received this error.

I also confirmed that my Execution Policy was still set to AllSigned.

Thursday, April 21, 2011

How to return data from a PowerShell function

Functions allow us to modularize our scripts and reuse code over and over again.  In some cases, you may want PowerShell to return information back to the parent scope so it can continue to be used.  Below is a very simple function.

Function DoMath
$a = 5 + 5


When we call this function, it returns our data.  We can set it up to return the data to a variable by calling the function with this command:

 $a = DoMath

The Return keyword is available. Return acts as a break for the function.  It will return the data specified, and stop processing the rest of the function.

Function DoMath
 $a = + 5
   Write-Host $a

Even though there is a Write-Host statement, the Return keyword prevents its execution.

Wednesday, April 20, 2011

Modify the Internet Explorer Compatibility List with PowerShell

Here is a good, real world question.  While examining the Group Policies settings for Internet Explorer in class.  The question came about as to whether or not the list can be modified in Group Policy by using PowerShell.  Well, yes you can.

The first thing is to determine what registry key we need to modify.  For the Compatibility list, the key is:
“HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Internet Explorer\BrowserEmulation\PolicyList”

To utilize PowerShell for this task, we first need to add the Group Policy Module.
Import-Module GroupPolicy

Next, to add the website names to the GPO named IE Settings, type:
Set-GPRegistryValue –Name “IE Settings” –Key “HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Internet Explorer\BrowserEmulation\PolicyList” –ValueName “” –Type String –Value “”

Opening the GPO in the Group Policy Management Editor and manually entering the web site would be faster for a single site.  But what if you have a whole list?  That is where we need to turn to a PowerShell script.

The PowerShell code below will allow you to populate the contents of a text file in the Internet Explorer 7 Compatibility list in the GPO of your choice.  This will remove any entries already in the GPO.  Each time it is ran, it purges the compatibility list and recreates it.  For that reason, use the text file as your master list for websites that need to be ran in compatibility mode.

To use this code, copy and paste it into your PowerShell ISE.  Change the file location for the text file and the name of the GPO and run it.

Script Name: ManageCompatabilityList.ps1
Version: 1.0
Author: Jason A. Yoder, MCT


Script Purpose:
This script will add websites to the Internet Explorer 7
Compatibility List in a Group Policy.  The website address
will come from a text file.  The text file will completely
manage what is contained in the Compatibility list GPO. If
a website is removed from the text file, or is not in the
it will also be removed from the GPO.

This script has only been tested on a Windows Server 2008 R2
domain controller.

Revision History:
Created: January 28, 2011
Status: Completed

# ===========================================================
# Global Variables

$Website_List = "E:\Compatibility List\Websites.txt"
# file and location of the text file holding the list of
# websites that need to be included in the Compatibility
# list of the GPO.

$GPOName = "IE Settings"
# This is the name of the Group Policy that contains the
# Compatibility List to be modified.

$ListKey = "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Internet Explorer\BrowserEmulation\PolicyList"
# The registry key to be modified. 

# == End of Global Variables ================================

# ===========================================================
# Main Code:

Import-Module GroupPolicy
# Imports the GroupPolicy cmdlets for PowerShell into this
# session.

$ErrorActionPreference = "SilentlyContinue"
# Should the Compatibility list inside the GPO be not
# configured, an error would be generated.  This allows
# the script to continue execution.

# Remove the current contents of the Compatibility List.
Get-GPRegistryValue -Name $GPOName -Key $ListKey | `
Remove-GPRegistryValue -Name $GPOName -Key $ListKey

# Load the list of websites into memory.
$Websites = Get-Content $Website_List

# Add each of the websites to the GPO
For ($i = 0; $i -le $Websites.count-1; $i++)
    Set-GPRegistryValue -Name $GPOName `
    -Key $ListKey -ValueName $Websites[$i] `
    -Type String -Value $Websites[$i]
$ErrorActionPreference = "Stop"
#Reset the error action mode of PowerShell.

# == End of Main Code =======================================

Tuesday, April 19, 2011

Creating a PowerShell Module

In Monday’s post, I showed you how to use Dot Sourcing to utilize the functions in one script, in the shell or in another script.  Today we are going to look at how to create a module.  First, we need to create a few files in your local profile.  We are going to call this our Library module.  Create the following folders inside your My Documents folder.


Now save this function to a script called Library.psm1.

Function Display-Info
 Write-Host (Get-WmiObject Win32_LocalTime).Year

Copy Libray.psm1 into the folder you just created.

Remember, the name of the .psm1 file needs to match the directory name.

Now, open a PowerShell session.

Type Get-Module –ListAvailable.  You should see your module listed.

Type Import-Module Library and press enter.

Now execute the function Display-Info.  The tab completion functionality of PowerShell should be available to you.

You can remove this module from memory by typing Remove-Module

Monday, April 18, 2011

Dot sourcing a PowerShell script.

PowerShell works in scopes.  At the very top layer, you have a global scope.  When you run a script, it is ran in a script scope inside the global.  If you run any functions inside that script, they run in their own function scope inside the script scope, which is inside the global scope.

When the function is finished and it exits its scope, all the data in the function is lost.  When the script ends, all of its data and the knowledge of the existence of the scripts functions are also lost.  What if you wanted to keep the functions from the script available to the shell?  That is where dot sourcing comes into play.


Let’s take a look at this simple function:


Function Display-Info
Write-Host (Get-WmiObject Win32_OperatingSystem).Caption



The output of this function, which changes depending on the client it is ran on, is:

Microsoft Windows 7 Ultimate

I know, this is a very simple function.  the problem is, after the execution is completed, I cannot use the function again in the shell.  To help solve this, I’m going to save this function as Library.ps1.  You can name it anything that you want.  I’m creating Library.ps1 to hold all the functions that I create and want to use in the shell or to make them available to my other PowerShell scripts.

I’m going to run this program in my shell environment.


I’m now going to attempt to execute the function directly from my shell.

No luck.


When I execute the command Dir Function: I can see that my function, Display-Info, is not listed.


I’m going to next dot source my library.ps1 script into the shell so that I can use its functions from within the shell and all scripts that I run in that shell session.

To do this, I execute the command . ./library.ps1.  Just so we are clear, the command is: Period – Space – Period – forward slash – library.ps1.


Now when I execute Dir Function:  I can see my function is listed.


I can now also execute it directly in the shell.


Just remember that once you close the shell, you will need to dot source your PowerShell script back in.  The dot sourcing puts the functions in the global scope.  When you close the global scope, you lose everything in it.

Friday, April 15, 2011

Enable Windows 7/2008 features using DISM offline servicing

One of the strong management points of Windows 7 deployment is the ability to manage you images without having to apply the image, make the changes, and then recapture the image.  DISM (Deployment Image Servicing and Management) allows you to mount a Windows image and make configuration changes to it.  All this while not having to take the time to first deploy the image.

To begin working with an image, we need to mount it.  First, make a new folder to hold the mounted image.  For this demo, I made one called ImageMount.  Both the folder and the image file are on my D: drive.

Next, open a command prompt with elevated permissions.
The .wim file I’m using for this demo is the install.wim file from the Windows Server 2008 R2 installation media.

Browse to the location where you stored the image file and the folder to mount it in.

Type DISM /mount-wim /wimfile:d:\install.wim /index:1 /Mountdir:d:\ImageMount

Depending on the size of the WIM file, this may take a few minutes,


Once completed, you can get information on the mounted WIM file by typing: DISM /get-mountedwiminfo and pressing Enter.


Here we are going to take a look at enabling and disabling features in a Windows 7 image.  To get a list of the features, type DISM /image:d:\ImageMount /get-features and press Enter.  Below is just a small sampling of what was returned.


We are going to enable the Printing-Server-Role

Type DISM /image:D:\ImageMount /enable-feature /FeatureName:Printing-Server-Role and press Enter.


You should see the message above if all went well.  By once again typing DISM /image:d:\ImageMount /get-features and pressing Enter, you should see the feature has been “Enable Pending.” This indicates the Optional Component is installed and enabled.


You can disable a feature by typing DISM /image:D:\ImageMount /Remove-feature /FeatureName:Printing-Server-Role and pressing Enter.

To commit the changes and close the image for use, type DISM /Unmount-Wim /MountDir:D:\ImageMount /Commit. If you do not want to save your changes, replace /Commit to /Discard.

Thursday, April 14, 2011

How to force a client to reboot with PowerShell

OK, the actual question from class was how to force a client to reboot while someone is logged in.  Be careful with this one.  This will not give the user at the other end the opportunity to save anything.

Restart-Computer –ComputerName ComputerName –Force

Don’t sweat, standard user accounts cannot shutdown a domain controller.  If you check the user rights on a domain controller, only the members of the Administrators, Backup Operators, Print Operators, and Server Operators groups can do this.  Everyone else gets this:
Restart-Computer : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))

Wednesday, April 13, 2011

What does the /Check switch do with the ImageX command?

ImageX allows us to work with images.  We can use ImageX to capture and apply them.  We can also mount the images for servicing. The /check switch will check the integrity of the .wim file when the command is executed. The /check switch is available to be used with the following ImageX operations:
  • /append
  • /apply
  • /capture
  • /delete
  • /export
  • /info
  • /mountrw
  • /split

Tuesday, April 12, 2011

How to Enable / Disable a basic GPO Setting with PowerShell

PowerShell allows you to make changes to your Group Policy objects.  This is a good way to create an automatic response to changes in your network environment.   The script below will show you how to configure a basic GPO setting.
A Basic GPO setting has three possible states:
  • Not Configured
  • Enabled
  • Disabled

We are going to use the GPO setting of Automatically Publish new Printers in Active Directory as our test subject.  A GPO called GPO-Test was created to house this setting. 
Using the Group Policy Settings Reference from Microsoft, I located the registry key in question:
HKLM\Software\Policies\Microsoft\Windows NT\Printers\Wizard!Auto Publishing
The value name is Auto Publishing.
When set to Enabled, the REG-DWORD is set to 0x00000001 (1)
When set to Disabled, the value is set to 0x00000000 (0)
When set to Not Configured, The value of Printers is not present in the registry.

This script is designed to show you how to achieve all three settings.  You can complete this task in just one command line.  Just take the code from one of the functions and plug in your values.  This code includes error checking in two areas that testing determined that an error could happen.

Script Name: BasicGPOSettings.ps1
Author: Jason A. Yoder, MCT
Script Purpose:
Demonstrate how to use PowerShell to change a basic
GPO Settings

- Must be ran on a Domain Controller or Windows 7 Client
  with RSAT installed.

- User must have the necessary permissions to modify
  the GPO.

Revision History:
Currently Version 1.0

Known Issues:

Set-StrictMode -version 2.0
# Variables:
# $GPOName: Holds the name of the Group Policy to be
# modified.
$GPOName = "GPO-Test"
# $ListKey : The registry key to be modified
$ListKey = "HKLM\Software\Policies\Microsoft\Windows NT\Printers\Wizard"
# $ListValueName : TheValueName to be changed.
$ListValueName = "Auto Publishing"
# $Decision : Will record the users choice on when
# value to set in the GPO.
$Decision = 0
# $QuestionString : String to display the valid choices
# to the user.
$QuestionString = "Please select from the following: 'r
1) - Set the policy to `"Enable`" `r
2) - Set the policy to `"Disabled`" `r
3) - Set the policy to `"Not Configured`" `r
4) - Retrieve the current policy information`" `r
5) - Exit the script without making changes"

# =========================================================

# =========================================================
# Functions:

# Enable_Setting will set the GPO value to "Enabled"
Function Enable_Setting
        Set-GPRegistryValue -Name $GPOName -Key $ListKey `
       -ValueName $ListValueName -Type DWORD -Value 1 
       Write-Host "The GPO value has been enabled."
# Disable_Setting will set the GPO value to "Disabled"
Function Disable_Setting
Set-GPRegistryValue -Name $GPOName -Key $ListKey `
       -ValueName $ListValueName -Type DWORD -Value 0  
        Write-Host "The GPO value has been disabled."
# Get_Current_Value will display the current value for the GPO setting.
# Error handling is set should this value be set to "Not Configured."
# In a "Not Configured" state, the GPO value is not present and would
# otherwise error out.
Function Get_Current_Value
        Try {Get-GPRegistryValue -Name $GPOName -Key `
        $ListKey -ErrorAction Stop}
        Catch { Write-Host "This GPO value is `"Not Configured`"."
                Write-Host "No data to return."}
# NC_Setting will set the GPO value to "Disabled"
# Error handling is set should this value be set to "Not Configured."
# In a "Not Configured" state, the GPO value is not present and would
# otherwise error out.
Function NC_Setting
        Write-Host "Setting the value to `"Not Configured`"."
        Try { Remove-GPRegistryValue -Name $GPOName -Key `
        $ListKey -ValueName $ListValueName -ErrorAction Stop}
        Catch { Write-Host "This GPO value is already set to `"Not Configured`"."}
# == End of Functions : ===================================
# =========================================================
# Main Code:

# Announce the start of the script.
Write-Host "=== Starting Script: BasicGPOSettings.ps1 ===" -foregroundcolor green

# Import the cmdlet needed for this operation from the
# GroupPolicy module
Import-Module GroupPolicy -cmdlet Set-GPRegistryValue, Remove-GPRegistryValue, Get-GPRegistryValue
# Display the users choices and record their decision in
# The variable $Decision.
$Decision = Read-Host ($QuestionString)
# Use the switch statement against $Decision to determine
# which function to execute.  Set the Switch statement to
# end on the first match. Set a DEFAULT value should the
# user select option 5 or provide an invalid input.
Switch ($Decision)
        1 {Enable_Setting; Break}
        2 {Disable_Setting; Break}
        3 {NC_Setting; Break}
        4 {Get_Current_Value; Break}
        Default {"No Changes Made"; Break}
# Announce the end of the script.
Write-Host "=== Ending Script: BasicGPOSettings.ps1 ===" -foregroundcolor green
# == End of Main Code =====================================

Monday, April 11, 2011

Create a Power Plan in Group Policy

With Group Policy Preferences, you can now design power plans for you organizations mobile users and deploy them using GPOs.  To access this feature, open or create a Group Policy.

Expand Computer Configuration \ Preferences \ Control Panel Settings \ Power Options.


When you right click Power Options and then select New, you get the option of creating Windows XP Power Options, Windows XP Power Scheme, or Windows Vista/7 Power Plan.  Remember, before you can use GPO Preferences on Windows XP, you need to install an update.  This article will help you with that.

Click Power Plan (Windows Vista and Later).

In the Action drop down list, you are given 4 choices.

The Create action will create a new power plan.

The Replace action will replace an existing power plan or create on if non exists.

Update will only changes settings that you specify, but will not remove any that are currently present

The Delete action will remove the power plan.


Under the Action drop down is another drop down box.  These are the Power plans currently on the server or Windows 7 client that you are creating the policy on.  You need to select which policy you want to make changes to.  If you want to keep the 3 default policies, first create a new Power Policy in the Control Panel and then restart this procedure.  In the example below, you can see that I created a Power Plan called My Custom Plan 1.  That will be the one I use in this demonstration.


Now you can examine each of the possible options and set each component to the proper settings for this plan.

Client OK when you are done.


You can see your power plan is now listed in the Power Options of the Group Policy Preference.  Close the Group Policy Management Editor window.  Apply this group policy in accordance with the configuration of your network.

On your Windows 7 client, click Start.

Type Power.

Click Power Options for the list.

Click the drop down arrow to the right of Show additional plans.

Notice that the custom plan you created in the Group Policy Preference is now listed.


Friday, April 8, 2011

Installing System Center Virtual Machine Manager

System Center Virtual Machine Manager (SCVMM) allows you to manage multiple virtualization hosts from one console.  With other virtual management software, you can only manage the virtual machines (VMs) on the local host.  With SCVMM, you can manage the VMs on hosts running Hyper-V, Virtual Server 2005 R2, and VMWare ESX Server.

First off, you need a copy of SCVMM.  You can download a 180 day trial version here. 
Once you download a copy, you simple need to install it.  First, execute the installation file with administrative level permissions.

Click VMM Server


Select I accept the terms of this agreement and click Next

On the Microsoft Update window, click what is appropriate for your environment and then click Next.

On the Customer Experience Improvement Program window, click what is appropriate for you and then click Next.

On the Product Registration page, enter your name and organization.  Click Next.

The Prerequisites Check page will automatically check for required components.  Fix any errors it detects. 

Click Next to continue.

On the Installation Location page, set the installation path and click Next.

On the SQL Server Settings page, choose the SQL installation that is appropriate for you.  Provide any required information for your organizations SQL setup.  Click Next.

On the Library Share Settings page, accept the defaults and click Next.

On the Installation Settings page, accept the defaults and click Next.

On the Summary of Settings page, click Install.

It is recommended that you leave Check for the latest Virtual Machine Manager updates checked. 

Click Close.

That’s all it takes.

Thursday, April 7, 2011

How to open PowerShell and specify the Execution Policy at the same time.

The PowerShell Execution Policy helps deter the accidental running of scripts.  To open PowerShell and specify the execution policy at the same time:

Click Start.

Type PowerShell –ExecutionPolicy Policy

Replace Policy with the Execution Policy level of your choice.

Wednesday, April 6, 2011

How to Change the metrics that VMM uses in placing VMs

System Center Virtual Machine Manager uses metrics on each managed host to determine if the host is suitable for the placement of a new VM.  The metrics that are evaluated are:
  • CPU Usage
  • Memory Free
  • Disk I/O
  • Network Utilization
These metrics are updated every 10 minutes.

You can configure VMM to place a higher or lower weight on each of these metrics to better fit your needs.  For example, if you are placing a high degree of emphasis on CPU utilization and you are deploying a VM that will require 4 CPUs, then only hosts with low CPU utilization will be selected for placement of that VM.  Here is how you can customized the metrics.


In the left pane at the bottom, click Administration

In the General pane, click Placement Settings.


The first two radio buttons allow you to balance the VM load or to maximize the servers resource utilization. 

The slider bars tell SCVMM what metrics are the most important to you.

Tuesday, April 5, 2011

Enumerate all Users that are assigned User Rights with PowerShell

One of the security questions that came up in my last PowerShell class was who has the User Rights to shut down a server. I went with this and created a script that searches all the User Rights that have a user or group assigned to them.  It performs a recursive search through all groups and provides you with a list of users who have that certain right.  Below is a screen shot part of the output.


Here is the PowerShell script.

Script Name:EnumerateUserRights.ps1
Author: Jason A. Yoder, MCT

Blog site:
Script Purpose:
Enumerates all the user accounts that are listed as having
a user right.  This script will do a recursive search
through all nested groups and will also report on user
accounts that have been directly assigned a User Right
outside of an Active Directory Group.

This script has been tested on a Domain Controller only.
The User rights were programed using the Default Domain
Controller Policy.

Revision History:
Version 2.0:
Now searches through all user rights.

Version 1.0:
Search only for Users who could shut down the

Known Issues:



$PolicyData : Holds the object of the user right for
               ShutDown server.

$UserList : Holds the names of all of the users found
            that have the User Right.
$UserObject : Holds the first name of the user. It is used
              to determine if a user account was directly
              assigned to the user right, as opposed to
              being assigned by a group.

$RightsAry : Holds the raw list of user rights extracted
           : from the server.


# =========================================================
# Functions:

# =========================================================
# Function: Get_Rights_Name:
# ---------------------------------------------------------
# This function will create a User friendly version of
# the User Right name that was extracted with WMI.
Function Get_Rights_Names ($Name)

    # Only process the data if it is of string
    # data type.
    If($Name -is [String])
        # Remove the surrounding double quotes and
        # the leading "Se".
        $Name = $Name.replace("`"Se","")
        $Name = $Name.replace("`"","")

        # Save an upper case version of the name in
        # $Data.
        $Data = $Name.ToUpper()

        # Make sure the variable $Final is empty.
        $Final = ""

        # Loop through the User Right name.
        # Identify the letters that are upper case
        # my using a case sensitive comparison
        # against both the original name, and
        # the upper case version.
        $i = While ($i -lt $Data.Length)

            # When an upper case letter is found,
            # Place a space in front of it.
            If ($Data[$i] -ceq $Name[$i])
                $Final += " "
                $Final += $Data[$i]

            # Write all lower case letters without
            # making any changes.
                    $Final += $Name[$i]

    # Trim any leading or trailing spaces from the
    # data.  Allow any errors here to pass without.
    # displaying error data.
    $ErrorActionPreference = 'SilentlyContinue'
    $Final = $Final.Trim()
    $ErrorActionPreference = 'Continue'

    # Write the header for the User Rights name.
    Write-Host "-- $Final ----------" `
        -ForegroundColor Yellow -BackgroundColor DarkGray


# =========================================================
# == Function: Enumerate_User_Rights                     ==
# ---------------------------------------------------------
# The below function will enumerate the User Rights that
# currently contain values.  It will return the values
# back to the script.

Function Enumerate_User_Rights
    # Get a string of all the __RELPATH properties that
    # contain the string "UserRight=".
    $RightsList = Get-WmiObject `
        -NameSpace Root\RSOP\Computer `
        -Class RSOP_PolicySetting | `
        Where {$_.PATH -match 'UserRight='}
    # Ensure this array has been cleared.
    $RightsArray = $NULL
    # Look through each object and select the string of
    # between the double quotes.  Add this data to
    # $RightsArray.  This process uses Regular
    # Expressions.  Type "Help About_Regular_Expressions"
    # for more information.
    foreach ($Rights in $RightsList)
        $MatchString = "`"\w*`""
        $Rights.__RELPATH -match $MatchString
        $RightsArray += $Matches.Values

    Return $RightsArray # Return the processed data.

# =========================================================
# Function: Enumerate_Users
# ---------------------------------------------------------
# Uses a WMI Query to list all the users and groups
# assigned to the User Right "Shutdown Server."
Function Enumerate_Users($RightsList)

# Feed the list of user rights.
ForEach ($RL in $RightsList)
    $UserList = $NULL
    If($RL -is [String])
      Get_Rights_Names $RL
        # Use WMI to extract the object for the user right
        # of Shutdown Server.
        $PolicyData = Get-WmiObject `
            -NameSpace Root\RSOP\Computer `
            -Class RSOP_PolicySetting |
            Where-Object {$_.__RELPATH -like "*$RL*"}

        # Loop through each object in the "AccountList"
        # property and recursively get the members of that
        # group.
        For ($i = 0 
             $i -le $PolicyData.AccountList.count-1

                # This first error handling will extract
                # the names of each User in each group
                # and nested group that have the right
                # to shutdown the server.
                Try {
                    $UserList += Get-ADGroupMember `
                        $PolicyData.AccountList[$i] `
                        -Recursive -ErrorAction Stop
                    # In the event that a user account is
                    # assigned directed to the user
                    # right as oppose through a group, this
                    # 'Catch' will allow the script to
                    # continue to the next 'Try'.

                # This error catch will extract a username
                # that was assigned directly to the User
                # Right.
                    # $UserObject will use Regular
                    # Expressions to remove the Domain name
                    # and backslash and return the given 
                    # name of the user.
                    $UserObject = $PolicyData.AccountList[$i] `
                        -replace "\w*\W"
                    # Get the full user name and add it to
                    # the $userList array.
                    $UserList += Get-ADUser -filter `
                        'GivenName -like $UserObject'
                        # This will let the error handling
                        # continue if a group is passed to
                        # it instead of a user.

    # Write the names of the users who have the User
    # Right that is being processed.
    $UserList | Sort-Object -Unique | format-Table Name

# == End of Functions : ===================================

# =========================================================
# Main Code:

# Announce the start of the script.
Write-Host "Script EnumerateUserRights.ps1 has started" `
    -ForegroundColor Green -BackgroundColor DarkBlue

# Import the Active Director cmdlets needed
#  for this script.
Import-Module ActiveDirectory -Cmdlet Get-ADGroupMember,

Clear-Host  # Clear the display

# Enumerate the User Rights that have assigned users
# and groups.
$RightsAry = Enumerate_User_rights

# Get the list of users who are assigned User Rights.
Enumerate_Users $RightsAry

    # Clears the data from memory.
    Clear-Variable -name UserList -ErrorAction Stop  
Catch{<# Do nothing, this is a none critical error.#>}
# Clears the data from memory.
Clear-Variable -name RightsAry
# Announce the end of the script.
Write-Host "Script EnumerateUserRights.ps1 has completed" `
    -ForegroundColor Green -BackgroundColor DarkBlue

# == End of Main Code =====================================