Advanced Windows PowerShell Scripting Video Training

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

Tuesday, May 31, 2011

Managed Deletion Protection on OUs, User, and Group objects with PowerShell

Below is a working PowerShell function that will help you enable/disable Deletion Protection on organizational units, user and group objects.  I included online help in this one so just dot source it or put it in a module to use it.  Once loaded, just type Get-Help Set-Deletion Protection –Full to see the entire help file and examples on how to use it.

There are actually two functions here.  The first supports the second.


Confirms if a module is available.


Confirms if the provided parameter is available on

the local client.

The name of the module who’s presence is being checked.
Confirm-Module ActiveDirectory
Checks to see if the ActiveDirectory module is
present on the local machine
Returns True is present and False if not.
Function Confirm-Module


Param ($ModuleName = $(Throw "You need to provide a module name."))

 # Place the name of the module from Get-Module into

 # the variable $Data

 $Data = (Get-Module -ListAvailable -Name $ModuleName).name

 # If the contents of $Data is equal to the variable
 # $ModuleName, the module is present, return
 # True.  If not, return $False.
 If ($Data -eq $ModuleName){Return $True}
 Else {Return $False}   

Ensures that Deletion Protection is set on AD Objects

Allows you to set the Deletion Protection on specific classes of objects in an Active Directory Environment.
This allows you to set Deletion Protection on both User and Group objects that otherwise do not have this capability in the Set-ADUser and Set-ADGroup cmdlets.

Sets whether to enable or disable Deletion Protection on the specified object classes.  This value must be set as $True or $False.

Targets the Organizational Units objects in Active Directory.

Targets the group objects in Active Directory.

Targets the user objects in Active Directory.

The name of the OU or Container to use as the root for processing the cmdlet . By default, all objects in the domain are processed for the object classes specified.

Set-DeletionProtection $True -OU

Protects all Organization Units in the domain from accidental deletion.

Set-DeletionProtection $True -User -Group

Protects all User and Group objects in the domain from accidental deletion.

Set-DeletionProtection $False -User -Root "IT Managers"

Removes Deletion Protection for all Users in the OU or Container whos' distinguished name contains "IT Managers"

Set-DeletionProtection $False -User -Root "IT"

The following OUs or Containers matched your Root parameter: IT.  Please select the index number of the OU or Container that you want to execute this cmdlet against.

Index DistinguishedName
----- -----------------
    0 CN=ForeignSecurityPrincipals,DC=Contoso,DC=com
    1 CN=IP Security,CN=System,DC=Contoso,DC=com
    2 CN=ComPartitions,CN=System,DC=Contoso,DC=com
    3 CN=ComPartitionSets,CN=System,DC=Contoso,DC=com
    4 OU=IT,DC=Contoso,DC=com
    5 OU=IT Test,OU=IT,DC=Contoso,DC=com

Index number:

In the above example, the cmdlet is attempting to remove deletion protection from all User Objects that is in an OU or Container that contains "IT" in the Distinguished Name.  The problem is that multiple OUs or Containers contain "IT" in them.  The menu presented above to the user will allow the user to choose the index number of the OU or Container to execute the cmdlet against.

Set-Deletionprotection $True -OU -Root "OfficeStaff"

No OU or Container matched your query.
The Cmdlet is terminating with no changes made.

The cmdlet above is attempting to enable Deletion Protection on all OUs or Containers with the name "OfficeStaff" in the Distinguished Name.  In this case, no OU or Container in the domain has the string "OfficeStaff: in it.

The Active Directory Module for PowerShell must be Available

Active Directory Users and Computers will be non- responsive while this cmdlet runs.


function Set-DeletionProtection
param (
   $Root = "*"

# Verify Boolean value for parameter $Enabled.
if ($Enabled.GetType().Name -ne "Boolean")
    Write-Host "Please supply a Boolean value of $True or $False"

# Test to verify that
if ((Confirm-module ActiveDirectory) -eq $True)
    # Import the Active Directory module.
    Import-Module ActiveDirectory -cmdlet Get-ADOrganizationalUnit, Set-ADOrganizationalUnit,
        Get-ADGroup, Get-ADUser, Set-ADObject
    Write-Host "Active Directory Module is not available."
-ForegroundColor Red -BackgroundColor Yellow

# If the $Root parameter is populated, make sure it points to a unique # container or OU.  If not, present the user with a list to choose from.
if ($Root -ne "*")

    $ObjList = @()

    $List = Get-ADObject -Filter * |
        Where-Object {($_.DistinguishedName -like "*$root*") -and (($_.ObjectClass -eq "OrganizationalUnit") -or ($_.ObjectClass -eq "Container"))}

    # Creates the index number should the query return
    # multiple matches.
    $i = 0

    # Loop through each returned item and enter the
    # data into an object to be used to determine
    # which object should be used.
    foreach ($Item in $List)
        $Object = New-Object PSObject
        $Object | Add-Member NoteProperty -Name DistinguishedName -Value $Item.DistinguishedName
        $Object | Add-Member NoteProperty -Name Index -Value $i
        $ObjList += $Object

    # If more than 1 OU or Container matches the query,
    # Present a menu to the user to choose from.
    if ($ObjList.Count -gt 1)
        Write-Host "---------------------------------------------"
-ForegroundColor Yellow
        Write-Host "The following OUs or Containers matched your"
        Write-Host "Root parameter: $Root.  Please select the"
        Write-Host "index number of the OU or Container that"
        Write-Host "you want to execute this cmdlet against."
        Write-Host " "
        $ObjList | FT Index, DistinguishedName -autosize
        Write-Host " "
        $Selection = Read-Host ("Index number")

        $Root = $ObjList[$Selection].DistinguishedName

    # If no OUs or Containers match the query, send
    # an error message and suspend the cmdlet.
    if (($ObjList.Count -eq 1) -and ($ObjList.DistinguishList -eq $Null))
        Write-Host "---------------------------------------------"
-ForegroundColor Red
        Write-Host "No OU or Container matched your query."
        Write-Host "The Cmdlet is terminating with no changes made."

    # If only one OU or Container matched the query
    # than use it
    if ($ObjList.Count -eq 1)
        $Root = $ObjList[0].DistinguishedName


# Configure Deletion protection for OUs.
if ($OU -eq $True)
    Get-ADOrganizationalUnit -Filter * |
    where {$_.DistinguishedName -like "*$root*"} |
    Where-Object {$_.ProtectedFromAccidentalDeletion -ne $Enabled} |
    Set-ADOrganizationalUnit -ProtectedFromAccidentalDeletion $Enabled
# End configuration for OUs.

# Configure Deletion protection for Groups.
if ($Group -eq $True)
     Get-ADGroup -Filter * |
     where {$_.DistinguishedName -like "*$root*"} |
     Where-Object {$_.ProtectedFromAccidentalDeletion -ne $Enabled} |
     Set-ADObject -ProtectedFromAccidentalDeletion $Enabled

# End configuration for Groups.

# Configure Deletion protection for Users.
if ($User -eq $True)
     Get-ADUser -Filter * |
     where {$_.DistinguishedName -like "*$root*"} |
     Where-Object {$_.ProtectedFromAccidentalDeletion -ne $Enabled} |
     Set-ADObject -ProtectedFromAccidentalDeletion $Enabled
# End configuration for Users.

Write-Host "Deletion protection changes in progress."
Write-Host "Active Directory Users and Computers may be un-responsive"
Write-Host "for a few seconds."

Monday, May 30, 2011

What is the actual initial file size of a dynamically expanding VHD?

In class I miss quoted Microsoft.  In Microsoft’s’ documentation, the actual wording is “the initial size of the .vhd file is only about 3 MB.”  So I created 4 dynamically expanding VHD files.  Their maximum sizes are 1GB, 10GB, 100GB, and 2TB.  Below is a screen shot of their initial sizes:


Saturday, May 28, 2011

Configuring VLANs in Hyper-V

The VLAN ID feature in Hyper-V allows you to support 802.1Q standards for VLAN Tagging. In short, it allows you to isolate hosts on the same physical network.


In the Hyper-V world, we can utilize VLAN IDs in two ways. We can isolate certain computers on the network or we can isolate VMs inside our hosts. First and foremost, your routers need to support and be configured with the VLAN identifiers. For the External and Internal virtual network configurations, you can isolate traffic to and from your host using a VLAN ID. You can do this for management purposes. As a result, only data tagged for the host VLAN will make it to your VMs. The other method is to configure the NICs of the VMs with a VLAN ID themselves. This is available in all three virtual network profiles. When used with the External profile, your VMs will only be able to communicate with VMs and physical host on your network with a matching VLAN ID.


Here is how you configure a virtual network with a VLAN ID.


In Hyper-V Manager, click Virtual Network Manager


Select External and click Add.




Check Enable virtual LAN identification for management operating system.


Select a number and click OK.



To configure a VM to use a VLAN:


Right click the VM you want to configure.


Click Settings


In the Hardware column, click the NIC you want to configure.


Check Enable virtual LAN identification.




Provide the VLAN number and then click OK

Friday, May 27, 2011

Will restoring a GPO from backup also restore the delegations?

Yes it will.  In class we assigned a delegation to a GPO and then backed it up by right clicking the GPO and selecting Backup. After the backup completed I removed the delegation.  I then right clicked the GPO and selected Restore.  Once the restore completed, the permissions for the GPO were all back.

Thursday, May 26, 2011

PowerShell Switch Parameter

One of the things that I’ve noticed in the PowerShell cmdlets are parameters without values.  These switches alter the way that the cmdlet functions without providing any input.  This is the switch parameter functionality.  Here is how it works. 

When you declare a parameter as a switch parameter, its value is set to $False.  Using what ever logic you like, you can test to see if the condition became $True.  That means the user executed the function and specified the switch.  Let’s look at a simple example:

function Test1 ([Int32]$Value,[switch]$Add5){
if ($Add5 -eq $True) {$Value += 5}
Write-Host $Value

In the function Test1, we have two values, a number and the switch parameter called $Add5.  This function is simple.  You provide it a number and it displays the number.  If you add the –Add5 parameter, it adds 5 to the number you provided.  Here is an example:

PS C:\Users\Jason> test1 5


PS C:\Users\Jason>

In the above example, we executed the script with the value of 5.  The result was 5.

PS C:\Users\Jason> test1 5 -Add5


PS C:\Users\Jason>

In this example, we included the –Add5 switch parameter.  In our code, we stipulated that if this parameter is $True, the we add 5 to the $Value that we gave the function.

The switch parameter functionality is good to use when you need to have a Boolean value as a parameter.

Wednesday, May 25, 2011

How many processors can Windows Serer 2008 R2 support?

According to Microsoft, Windows Server 2008 R2 can support up to 256 logical processors.  Just to get a visualization, I found an image of task manager with this configuration.

Here is the next question.  What application can cause such a high processor utilization?

Tuesday, May 24, 2011

Set forest and domain modes with PowerShell

Both the domain and forest functional modes in a Windows domain will determine what functionality that you get.  When you purchase a new Windows Server OS, it comes with more advanced functionality than the previous version.  Some of that functionality may not be compatible with previous versions of the server OS.  In order to raise the functional level to say, Windows Server 2008, you need to upgrade all your domain controllers to a minimum of Windows Server 2008.  You can still have Windows 2000 and 2003 member servers, just not as domain controllers.

You can use PowerShell to raise both your functional levels.  Here is an example of how to raise both levels to Windows Server 2008 R2.

Open PowerShell
Import-Module ActiveDirectory
Set-ADDomainMode –Identity (Get-ADDomain) –DomainMode Windows2008R2Domain
Set-ADForestMode –Identity (Get-ADDomain) –DomainMode Windows2008R2Forest

The valid values are:

ID Domain Forest
0 Windows2000Domain Windows2000Forest
1 Windows2003InterimDomain Windows2003InterimForest
2 Windows2003Domain WIndows2003Forest
3 Windows2008Domain Windows2008Forest
4 WIndows2008R2Domain Windows2008R2Forest