Quantcast
Channel: Hey, Scripting Guy! Blog
Viewing all 3333 articles
Browse latest View live

Weekend Scripter: Use PowerShell to Get, Add, and Remove NTFS Permissions

$
0
0

Summary: Microsoft PFE, Raimund Andree, talks about using Windows PowerShell to get, add, and remove permissions.

Microsoft Scripting Guy, Ed Wilson, is here. Today we have Microsoft Premier Field Engineer, Raimund Andree, back to talk about using Windows PowerShell to work with permissions...

Managing file and folder permissions in Windows PowerShell is not that easy, and there are numerous articles and blog posts describing how it works by using the .NET classes. This is far from being comfortable, and there is one major and one minor restriction:

  • Path length
  • Generic rights

This post introduces the NTFSSecurity module, which provides a bunch of cmdlets for managing permissions on NTFS drives. It does not use the Windows PowerShell way to access the file system, and it works around the MAX_PATH, which is 260 characters. (For more information, see Naming Files, Paths, and Namespaces). This is achieved thanks to AlphaFS.

This post examines displaying permissions and granting users permission.

Installation

You can download the module from the Script Center Repository: File System Security PowerShell Module 3.2.1. Please unblock the file before extracting it.

For more information about installing Windows PowerShell modules, see Hey, Scripting Guy! How Can I Install Windows PowerShell Modules on Multiple Users' Computers?

Some background

Windows stores the permissions in the discretionary access control list (DACL), which is part of the Security Descriptor. The Security Descriptor also includes the system access control list (SACL), where the auditing is configured, and member information. This post is about permissions and it does not discuss the SACL or member information.

The DACL contains access control entries (ACEs) that define the permissions someone has on the object. Each ACE contains the following values:

  • Account: Who is granted or denied access. Windows does not store the user’s SamAccountName, but rather, the SID.
  • Rights: The permissions granted or denied.
  • Type: Grant or deny access.
  • IsInherited: True if the ACE is inherited from a parent object.
  • InheritanceFlags and PropagationFlags: These bits control the inheritance. The NTFSSecurity module converts the bits into something more readable that is discussed later in this post.

By default, a security descriptor on the file system inherits permissions from the parent object. Users who have full access on drive C also have full access to all subfolders if the inheritance is not disabled.

Managing permissions

Reading the permissions of a single item

The first and easiest task is to retrieve the DACL from a specific file. The cmdlet that the NTFSSecurity module provides for retrieving existing permissions is Get-NTFSAccess. You can pipe a file or folder to that cmdlet or work with the Path parameter:

Get-Item D:\Data | Get-NTFSAccess

Get-NTFSAccess -Path D:\Data

The output might look like this:

Image of command output

The output is grouped by the file or folder, which is important when getting the permissions of more than one object. Next to the path is information about if the file or folder inherits the permissions from the parent object. My example shows that four of the displayed ACEs have been inherited from drive D.

Some more details about the columns:

  • Account: The account that has been granted or denied access to the item. As mentioned, Windows does not store the user’s name, but rather, the SID. If the SID can be translated into the name, NTFSSecurity shows it; otherwise, the SID is displayed.
  • AccessRights: These are the actual permissions that the account has been granted or denied. The list behind this field also supports generic rights.
  • Applies to: The .NET Framework stores the inheritance information in two-bit fields: InheritanceFlags and PropagationFlags. These fields are quite difficult to interpret, so NTFSSecurity converts them into something that is known from the Windows Explorer:
    • ThisFolderOnly
    • ThisFolderSubfoldersAndFiles
    • ThisFolderAndSubfolders
    • ThisFolderAndFiles
    • SubfoldersAndFilesOnly
    • SubfoldersOnly
    • FilesOnly
  • Type: Either Allow or Deny
  • Inherited: If the ACE is inherited from the parent, this is True. The first two ACEs have been defined explicitly in the folder.
  • InhertedFrom: This column only contains information if IsInherited is True, and it indicates where the ACE is inherited from.

Reading the permissions of multiple items

All NTFSSecurity cmdlets support pipelining. If you need to get the permissions from multiple items, you do not need to run a ForEach loop. You can simply pipe the files and folders to Get-NTFSAccess.

dir C:\Data | Get-NTFSAccess

Get-NTFSAccess provides ways to filter the ACEs. A common scenario is to get the ACEs of a specific account or only those that have not been inherited.

If you want to display only permissions that have been added explicitly and hide all the inherited permissions, use the ExcludeInherited switch:

dir | Get-NTFSAccess –ExcludeInherited

If you want to display only the permissions assigned to a certain user, use the Account parameter:

dir | Get-NTFSAccess -Account raandree9\randr_000

Note  This displays the permissions as defined in the ACL. This is not the effective permissions. Effective permissions will be discussed in an upcoming post.

Granting access

Granting access to a file or folder is also quite easy to do by using the Add-NTFSAccess cmdlet. Add-NTFSAccess provides the following parameters:

  • Account: This can be a user account name (SamAccountName) or a SID. The user account name has to contain the domain (domain\username). Built-in SIDs are also supported, such as Everyone, NT AUTHORITY\SYSTEM, or BUILTIN\Administrators. For more information, see Well-known security identifiers in Windows operating systems.
  • AccessRights: This parameter takes one or more of file system rights, for example, FullControl, Modify, or Read. If you want to assign multiple rights, provide them in a comma-separated list.

Note  Use Tab expansion or the ISE to get a list of all available values.

  • AccessType: Allow or deny
  • AppliesTo: This parameter sets the scope of the ACE. The options are the same as Windows Explorer provides. By default (when not defined), the scope is ThisFolderSubfoldersAndFiles.

Note  Use Tab expansion or the ISE to get a list of all available values.

  • PassThru: By default, the cmdlet does not return any data. If the PassThru switch is used, the cmdlet displays the ACL after adding the ACE.

The next commands give the well-known group, Authenticated Users, read access to the folder C:\Data. The built-in administrators and the local group, Editors, are getting full control:

Add-NTFSAccess -Path C:\Data `

    -Account 'NT AUTHORITY\Authenticated Users' `

    -AccessRights Read

 

Add-NTFSAccess -Path C:\Data `

    -Account 'BUILTIN\Administrators', 'raandree9\Editors' `

    -AccessRights FullControl

Removing access

Removing access is similar to adding permissions. The command Remove-NTFSAccess takes the same parameters as Add-NTFSAccess.

To remove a user from the ACL, provide the path, the account name, and the permissions you want to remove, for example:

Remove-NTFSAccess D:\Data -Account RAANDREE0\randr_000 -AccessRights Read -PassThru

If the user has different permissions than those you want to remove, nothing happens. There needs to be an exact match.

Note  You cannot remove inherited permissions. Get-NTFSAccess informs about the source of the inherited permissions where the respective ACE can be changed or removed.

Remove-NTFSAccess accepts pipeline input. If you want to remove all permissions for a certain user account, you can read the permissions first and then pipe the results to Remove-NTFSAccess. This operation can also run reclusively:

Get-ChildItem -Path d:\ -Recurse |

    Get-NTFSAccess -Account raandree0\randr_000 -ExcludeInherited |

    Remove-NTFSAccess

Note  The cmdlets in the NTFSSecurity module do not provide a way to process files and folders reclusively. You have to use Get-ChildItem or Get-ChildItem2 with the Recurse switch. (The Get-ChildItem2 cmdlet is part of the NTFSSecurity module, and it will be discussed in a future post.)

NTFS inheritance

After you set permissions on a parent folder, new files and subfolders that are created in the folder inherit these permissions. If you do not want them to inherit permissions, set ApplyTo to “ThisFolderOnly” when you set special permissions for the parent folder. In cases where you want to prevent certain files or subfolders from inheriting permissions, disable (or block) the inheritance.

There are two types of permissions:

  • Explicit permissions: Set by default when the object is created by user action.
  • Inherited permissions: Propagated to an object from a parent object. Inherited permissions ease the task of managing permissions and ensure consistency of permissions among all objects within a given container.

To add an ACE that does not affect any child elements, use the following command:

Add-NTFSAccess .\Data -Account raandree1\install -AccessRights Modify -AppliesTo ThisFolderOnly

If the AppliesTo parameter is not used, the ACE applies to “ThisFolderSubfoldersAndFiles,” like when using the Windows Explorer to add permissions. All child elements will inherit the ACE created by the following command:

Add-Access -Path .\Data -Account BUILTIN\Administrators -AccessRights FullControl

To verify which child items have inherited the ACE, you can get and pipe all child elements recursively to Get-NTFSAccess. With the following command, Windows PowerShell reads only the inherited ACEs that are assigned to the built-in administrators group that are inherited from D:\Data:

dir -Recurse | Get-NTFSAccess -Account BUILTIN\Administrators -ExcludeExplicit | Where-Object InheritedFrom -eq 'D:\Data' 

Image of command output

The next post will explore how to report, enable, and disable inheritance in folders (the NTFSSecurity module provides the same feature as the Windows Explorer). I will also discuss taking ownership of files without losing the ACL.

~Raimund

Thank you, Raimund, for an awesome blog post.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 


PowerTip: Use PowerShell to Show Hidden Files

$
0
0

Summary: Use Windows PowerShell to display only hidden files.

Hey, Scripting Guy! Question How can I see hidden files by using Windows PowerShell 4.0?

Hey, Scripting Guy! Answer Use the Get-ChildItem cmdlet, and add the –Hidden and the –File switches:

Get-ChildItem -Hidden -File

Weekend Scripter: Manage NTFS Inheritance and Use Privileges

$
0
0

Summary: Microsoft PFE, Raimund Andree, talks about using Windows PowerShell to disable inheritance on folders.

Microsoft Scripting Guy, Ed Wilson, is here. Today Raimund Andree, talks about using Windows PowerShell to disable inheritance on folders. Take it away, Raimund...

In my previous post, Use PowerShell to Get, Add, and Remove NTFS Permissions, I talked about NTFS inheritance. Inheritance is a fundamental feature of NTFS to keep permissions consistent and easy to manage.

However, there are some scenarios where you want to disable inheritance on folders or find out where it has been disabled. This post explains how this can be achieved by using the NTFSSecurity module.

Determine inheritance settings

To determine if a file or folder inherits from its parent, use the Get-NTFSAccessInheritance cmdlet (there is also a Get-NTFSAuditInheritance cmdlet). There are two ways to specify the file or folder: You can use the Path parameter or pipe the file or folder object to Get-NTFSAccessInheritance:

Get-NTFSAccessInheritance -Path C:\Windows

Get-Item C:\Windows | Get-Inheritance

The output might look like this:

Image of command output

You can easily get the information for a bunch of items by using the built-in Get-ChildItem cmdlet, and then pipe all the items to Get-NTFSAccessInheritance:

Get-ChildItem c:\ | Get-NTFSAccessInheritance

Image of command output

Enabling inheritance

The cmdlet for enabling the inheritance on an object is similar to reading the inheritance information:

Enable-NTFSAccessInheritance -Path .\Data

By default, the cmdlet does not return any output unless you use the PassThru switch.

The cmdlet provides one additional switch parameter: RemoveExplicitAccessRules. When specified, all explicitly assigned access control entries (ACEs) will be removed after enabling the inheritance. This is like setting the folder back to default permissions.

Image of command output

The previous output shows that there were only explicitly assigned ACEs in the Data folder. These were removed after enabling the inheritance and there are only inherited ACEs remaining.

Note  The RemoveExplicitAccessRules switch should be used with care. Using this switch by accident can cause users to not be able to access their resources.

A common use case for Enable-NTFSAccessInheritance

If users can alter the ACL of files or folders, they might remove relevant ACEs. The result is that the administrators are no longer able to access the data. Another reason why an administrator cannot access data is that someone has disabled the inheritance and deleted all inherited ACEs.

First you need to use the recursive method provided by Get-ChildItem to get all files and folders and filter out the items where inheritance is enabled.The remaining items are piped to Enable-NTFSAccessInheritance, which informs about items where inheritance is enabled with the PassThru switch.

Get-ChildItem -Recurse | Get-NTFSAccessInheritance | Where-Object { -not $_.InheritanceEnabled } |
Enable-NTFSAccessInheritance -PassThru

Image of command output

Disabling inheritance

In NTFSSecurity, you also need to disable inheritance. When enabling inheritance you have to determine what to do with explicit ACES (usually you keep them). When disabling inheritance, the inherited ACEs can be converted into explicit ones or they can be removed. This is controlled by the RemoveInheritedAccessRules switch.

In the following example, the inheritance for the folder GPO is enabled. The folder is inheriting four ACEs from the parent (drive D). After disabling inheritance, the ACEs still exist as explicit ACEs.

Image of command output

Note  When using the RemoveInheritedAccessRules switch, you need to make sure that the access is guaranteed after disabling the inheritance. If an item does not have explicit ACEs assigned and you remove all inherited ACEs, nobody will be able to access the file. However, an administrator can always use the back-up privilege or take ownership to get access again.

Using privileges

Note  There was a big change in Windows 8 and Windows Server 2012 regarding how privileges can be used. The features described in this section work only on Windows 8.1, Windows 8, Windows Server 2012 R2, and Windows Server 2012.

Sometimes permissions are hosed and access is denied, even if you are the mighty administrator. In this case, you cannot even read the existing ACL. Of course, the administrator can always take the ownership of an object, but this erases the existing ACL of the object. This is bad because you cannot determine by the ACL the people who need to have access.

Windows has a very handy concept of privileges. A privilege represents the right of an account, such as a user or group account, to perform various system-related operations on the local computer, such as shutting down the system, loading device drivers, or changing the system time. Privileges differ from access rights in two ways:

  • Privileges control access to system resources and system-related tasks, whereas access rights control access to securable objects.
  • A system administrator assigns privileges to user and group accounts, whereas the system grants or denies access to a securable object based on the access rights granted in the ACEs in the object's DACL.

When dealing with files and folders, three privileges are worth looking at:

  • Back up files and directories:
    This user right determines which users can bypass file and directory, registry, and other persistent object permissions for the purposes of backing up the system. By default, Administrators and Backup Operators can make use of this privilege.
  • Restore files and directories:
    This security setting determines which users can bypass file, directory, registry, and other persistent objects permissions when restoring backed up files and directories, and it determines which users can set valid security principals as the owner of an object.

    Specifically, this user right is similar to granting the following permissions to the user or group in question on all files and folders on the system:
    • Traverse Folder/Execute File
    • Write

    By default Administrators and Backup Operators have this privilege assigned.

  • Take ownership of files or other objects:
    This security setting determines which users can take ownership of any securable object in the system, including Active Directory objects, files and folders, printers, registry keys, processes, and threads. By default, this privilege is assigned to Administrators.

For a list of privileges, refer to Privileges in the TechNet Library.

To create the situation described previously, you can use the following command sequence:

Set-NTFSOwner .\Data -Account 'NT AUTHORITY\SYSTEM'

Disable-NTFSAccessInheritance .\Data -RemoveInheritedAccessRules

The first command assigns the ownership of the Data folder to the SYSTEM account, and the second command disables the inheritance. Now only the SYSTEM account can access the item.

Image of command output

Windows Explorer is not helpful either:

Image of message

Enabling privileges

The NTFSSecurity module provides the Enable-Privileges cmdlet. This cmdlet enables the privileges Backup, Restore, and Security (if you have them). You can get a list of available privileges by using Get-Privilege.

Running Get-Privilege in a non-elevated Windows PowerShell console should return something like this:

Image of command output

The privileges Backup, Restore, and Security are missing. If you run the same command in an elevated Windows PowerShell console, the list gets much longer:

Image of command output

All these privileges are disabled by default. Having them enabled all the time would be quite dangerous and would increase ones scope of action too much. However in some scenarios, it is required to make use of privileges, for example, when doing backup jobs, data migrations, or permission cleanups.

To enable the privileges, call Enable-Privileges. You will get a warning message that informs you about the enabled privileges.

Note  If you call the cmdlet in a non-elevated Windows PowerShell console, and hence, you do not hold the proper privileges, the following error message returns:
Enable-Privileges: Could not enable requested privileges. Cmdlets of NTFSSecurity will only work on resources you have access to.

After calling Enable-Privileges, you can check the state of the privileges by using Get-Privileges.

Using enabled privileges

Enabling the privileges is pretty much all you need to do. The process that has enabled them uses them automatically.

After removing the permissions from the Data folder, there is no way to access it or display the owner or ACL. However, after enabling the privileges, Windows bypasses the ACL and grants you full access (thanks to the Backup and Restore privilege).

Image of command output

Get-NTFSAccess does not return any data because there is no ACE in the ACL. Remember that all ACEs have been removed by disabling the inheritance.

Now you can take the ownership and enable inheritance again:

Set-NTFSOwner -Path .\Data -Account BUILTIN\Administrators

Enable-NTFSInheritance -Path .\Data

Image of command output

Now the access is how it should be again.

Disabling privileges

If you no longer need the privileges, it is strongly recommended to disable them. Use the command Disable-Privileges for this.

After calling Disable-Privileges, you can check the state of the privileges by using Get-Privileges.

~Raimund

Thank you again, Raimund, for an informative blog post.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Use PowerShell to Find If Folder Inherits from Parent

$
0
0

Summary: Use Windows PowerShell to determine if an NTFS folder inherits from its parent folder.

Hey, Scripting Guy! Question How can I use Windows PowerShell to determine if an NTFS folder inherits from its parent folder?

Hey, Scripting Guy! Answer Use the Get-NTFSAccessInheritance cmdlet provided by the NTFSSecurity module, for example:

Get-NTFSAccessInheritance -Path C:\Windows

Or if you want to query multiple folders:

dir -Recurse | Get-NTFSAccessInheritance | Where-Object { -not $_.InheritanceEnabled }

Active Directory Week: Get Started with Active Directory PowerShell

$
0
0

Summary: Microsoft premier field engineer (PFE), Ashley McGlone, discusses the Active Directory PowerShell cmdlets.

Microsoft Scripting Guy, Ed Wilson, is here. Today we start a series about Active Directory PowerShell, written by Ashley McGlone...

Ashley is a Microsoft premier field engineer (PFE) and a frequent speaker at events like PowerShell Saturday, Windows PowerShell Summit, and TechMentor. He has been working with Active Directory since the release candidate of Windows 2000. Today he specializes in Active Directory and Windows PowerShell, and he helps Microsoft premier customers reach their full potential through risk assessments and workshops. Ashley’s TechNet blog focuses on real-world solutions for Active Directory using Windows PowerShell.  You can follow Ashley on Twitter, Facebook, or TechNet as GoateePFE.

Since I joined Microsoft, the Scripting Guy and the Scripting Wife have become dear friends. Ed has mentored my career and opened doors for me as I engaged the Windows PowerShell community. It is an honor for me to write this week’s blog series about Active Directory PowerShell as Ed is taking some personal time off. Thank you, Ed.

Active Directory PowerShell

Perhaps your job responsibilities now include Active Directory, or perhaps you are finally moving off of Windows Server 2003. There is no better time than the present to learn how to use Windows PowerShell with Active Directory. You will find that you can quickly bulk load users, update attributes, install domain controllers, and much more by using the modules provided.

Background

The Active Directory PowerShell module was first released with Windows Server 2008 R2. Prior to that, we used the Active Directory Services Interface (ADSI) to script against Active Directory. I did that for years with VBScript, and I was glad to see the Windows PowerShell module. It certainly makes things much easier.

In Windows Server 2012, we added several cmdlets to round out the core functionality. But we also released a companion module called ADDSDeployment. This module replaced the functionality we had in DCPROMO. With Windows Server 2012 R2 we added some cmdlets for the new authentication security features.

Image of flow chart

Now we have a fairly robust set of cmdlets to manage directory services in Windows.

How do I get these cmdlets?

The version of the cmdlets you use depends on the Remote Server Administration Tools (RSAT) that you install, and that depends on the operating system you have. See the following graphic to determine which version of the cmdlets you should use.

Image of flow chart

For example, if you have Windows 7 on your administrative workstation, you can use the first release of the ActiveDirectory module. The cmdlets can target any domain controller that has the AD Web Service.  (Windows Server 2008 and Windows Server 2003 require the AD Management Gateway Service as a separate installation. For more information, see Step-by-Step: How to Use Active Directory PowerShell Cmdlets against Windows Server 2003 Domain Controllers.)

If you have a Windows 8.1 workstation, you can install the latest version of the RSAT and get all the fun new cmdlets, including the ADDSDeployment module. If you are stuck in Windows 7, and you want to use the latest cmdlets, see How to Use The 2012 Active Directory PowerShell Cmdlets from Windows 7 for a work around.

Alternatively, if you use a Windows Server operating system for your tools box, you can install the AD RSAT like this:

Install-WindowsFeature RSAT-AD-PowerShell

The following command will give you all of the graphical administrative tools and the Windows PowerShell modules:

Install-WindowsFeature RSAT-AD-Tools -IncludeAllSubFeature

Where do I begin?

I recommend for most people to start with the Active Directory Administrative Center (ADAC). This is the graphical management tool introduced in Windows Server 2012 that uses Windows PowerShell to run all administrative tasks.

The nice part is that you can see the actual Windows PowerShell commands at the bottom of the screen. Find the WINDOWS POWERSHELL HISTORY pane at the bottom of the tool, and click the Up arrow at the far right of the window. Select the Show All box. Then start clicking through the administrative interface. You can see the actual Windows PowerShell commands being used:

Image of menu

Yes. Read the Help.

If you are using Windows PowerShell 4.0 or Windows PowerShell 3.0 or newer, you need to install the Help content. From an elevated Windows PowerShell console type:

Update-Help -Module ActiveDirectory -Verbose

Although it is optional, I usually add the ‑Verbose switch so that I can tell what was updated. This also installs the Active Directory Help topics:

Get-Help about_ActiveDirectory -ShowWindow

Get-Help about_ActiveDirectory_Filter -ShowWindow

Get-Help about_ActiveDirectory_Identity -ShowWindow

Get-Help about_ActiveDirectory_ObjectModel -ShowWindow

Note that you may have to import the Active Directory module before you can discover the about_help topics:

Import-Module ActiveDirectory

You can also find these Help topics on TechNet: Active Directory for Windows PowerShell About Help Topics.

I strongly advise reading through these about_help topics as you get started. They explain a lot about how the cmdlets work, and it will save you much trial and error as you learn about new cmdlets.

Type your first commands

Now that you have the module imported, you can try the following commands from the Windows PowerShell console:

Get-ADForest

Get-ADDomain

Get-ADGroup “Domain Admins”

Get-ADUser Guest

Congratulations! You are now on your way to scripting Active Directory.

Move to Active Directory PowerShell cmdlets

The next step is to replace the familiar command-line utilities you have used for years with new Windows PowerShell commands. I have published a four page reference chart to help you get started: CMD to PowerShell Guide for Active Directory.

For example, instead of the DSGET or DSQUERY command-line utilities, you can use Get‑ADUser, Get‑ADComputer, or Get‑ADGroup. Instead of CSVDE, you can use Get‑ADUser | Export‑CSV.

With this knowledge, you can find some of your batch files or VBScripts for Active Directory and start converting them to Windows PowerShell. Beginning with a goal is a great way to learn.

Ready, Set, Go!

I hope you have enjoyed this quick start for Active Directory PowerShell. You now have the necessary steps to get started on the journey. Stay tuned this week for more posts about scripting with Active Directory. You can also check out four years of Active Directory scripts over at the GoateePFE blog.

~ Ashley

Thanks for the beginning of a great series, Ashley! Ashley recently recorded a full day of free Active Directory PowerShell training: Microsoft Virtual Academy: Using PowerShell for Active Directory. Watch these videos to learn more insider tips on topics like getting started with Active Directory PowerShell, routine administration, stale accounts, managing replication, disaster recovery, and domain controller deployment.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Find PowerShell Help Topics for Active Directory

$
0
0

Summary: Find the Windows PowerShell help_about topics for Active Directory.

Hey, Scripting Guy! Question Where are the Windows PowerShell help_about topics for Active Directory?

Hey, Scripting Guy! Answer If you have Windows 7 or Windows Server 2008 R2 with the Active Directory Remote Server Administration Tools
           (RSAT) installed, you also have the Active Directory Help topics.

  If you have Windows PowerShell 4.0 or Windows PowerShell 3.0 installed, you can run the following command
  from an elevated Windows PowerShell console to install them:

Update-Help -Module ActiveDirectory -Verbose

To view the topics, you must first import the module:

Import-Module ActiveDirectory

Now try the following commands:

Get-Help about_ActiveDirectory

Get-Help about_ActiveDirectory_Filter

Get-Help about_ActiveDirectory_Identity

Get-Help about_ActiveDirectory_ObjectModel

You can also find these Help topics on TechNet: Active Directory for Windows PowerShell About Help Topics.

Active Directory Week: Explore Group Membership with PowerShell

$
0
0

Summary: Learn about the nuances involved in reporting group memberships with Active Directory PowerShell.

Microsoft Scripting Guy, Ed Wilson, is here. Today we continue our series about Active Directory PowerShell by Ashley McGlone. If you missed it, you may enjoy reading Get Started with Active Directory PowerShell first. Now, here's Ashley...

Security priority

In our world today, security is getting more focus with every headline about data breaches. One key strategy to keep your environment secure is regular audits of group memberships. Hopefully, you or your company’s information security team are regularly checking group memberships. For example, I’ve met many customers who get an email every time a sensitive group membership changes (for example, JoeUser was added to Enterprise Admins).

Who’s on first?

In, there are multiple techniques for reporting group memberships. Today, I will share with you some of the nuances involved. Here are the questions we really want to answer on an operational level with scripting:

  • Who are all of the Domain Admins? (Traversing down the membership tree)
  • Is JoeUser a member of Domain Admins? (Traversing up the membership tree)
  • How did JoeUser get added? (By whom? When? Where?)

Image of flow chart

I’ve referenced the Domain Admins group here—but you could substitute any group name of interest.

Down the rabbit hole

Group nesting makes these questions a challenge for new scripters. I’ve seen people write some rather interesting code to do their own recursion routines to mine group memberships. Although those are fun to write, there are some built-in cmdlets to help. Let’s look at what you get for free before launching into a scripting project.

Who are all the Domain Admins?

The cmdlet Get-ADGroupMember gives you a list of group members. (I’ve heard some complaints that it doesn’t do too well with cross-domain memberships, however.) Immediate members are helpful, but we want to know who is a member of all those nested groups. Thankfully, the cmdlet has a ‑Recursive parameter. Here is a quote from the Help:

If the Recursive parameter is specified, the cmdlet gets all members in the hierarchy of the group that do not contain child objects. For example, if the group SaraDavisReports contains the user KarenToh and the group JohnSmithReports, and JohnSmithReports contains the user JoshPollock, then the cmdlet returns KarenToh and JoshPollock.

Note  When you use this parameter you will not see the nested group names, only the members of all the nested groups. The nice thing here is that you can get all true group members even if a user is nested in groups many layers deep.

The -Recursive parameter is resource intensive and should be used with care. Be a good steward of resources by running your query once and storing it in a variable. Then work with the variable instead of issuing the same query multiple times.

$members = Get-ADGroupMember “Domain Admins” -Recursive

Going the other way

What if I want to start with the user and find all of their group memberships recursively (that is, going up the membership tree)? The Get-ADPrincipalGroupMembership cmdlet is your first choice. Here is a quote from the Help:

The Get-ADPrincipalGroupMembership cmdlet gets the Active Directory groups that have a specified user, computer, group, or service account as a member. This cmdlet requires a global catalog to perform the group search. If the forest that contains the user, computer or group does not have a global catalog, the cmdlet returns a non-terminating error. If you want to search for local groups in another domain, use the ResourceContextServer parameter to specify the alternate server in the other domain.

It has bells and whistles for a number of search scenarios. By best practice, all of your domain controllers are likely global catalogs, so that requirement should not be a concern.

            $members = Get-ADPrincipalGroupMembership JoeUser

However, this cmdlet does not have a parameter to do a recursive nested group search. It only shows the immediate group membership of a user. If you want to map out all of the nested group memberships, see Token Bloat Troubleshooting by Analyzing Group Nesting in AD on the Active Directory PowerShell blog.

Is JoeUser a nested member of Domain Admins?

How can I traverse up the group nesting to check if JoeUser is in Domain Admins? You do not need to reinvent the wheel. You do not need to write a bunch of code to trace all the nested groups. This happens to be a little-known feature built into the LDAP protocol, and it is supported by Windows Server 2008 and later. I discovered this trick when reading through the Get-Help about_ActiveDirectory_Filter Help topic under Example 11. To quote the Help:

The LDAP_MATCHING_RULE_IN_CHAIN is a matching rule OID that is designed to provide a method to look up the ancestry of an object.

We can use the -RecursiveMatch operator in a filter string to employ this LDAP feature. It searches all of the parent-child relationships of any Active Directory object.

Pro Tip  If you cannot find the about_ActiveDirectory* Help topics, first make sure you have the RSAT installed for Active Directory. Then run Update-Help -Module ActiveDirectory in an elevated Windows PowerShell console (version 4.0 or 3.0). You must import the Active Directory module before the topics will be available.

Check out this syntax:

Get-ADUser -Filter 'memberOf -RecursiveMatch "<distinguished name of group>"' -SearchBase "<distinguished name of user>"

Here is an example:

Get-ADUser -Filter 'memberOf ‑RecursiveMatch "CN=Administrators,CN=Builtin,DC=Fabrikam,DC=com"' ‑SearchBase "CN=Administrator,CN=Users,DC=Fabrikam,DC=com"

If the user is a member of the group, the query will return an AD object representing the user. If not a member of the group, the query will return nothing. The beauty is that it does all of the recursive group checking for you.

Now let’s make this more interesting. I really don’t like typing those long Active Directory distinguished names, and it is easier to supply these from a query like this:

Get-ADUser -Filter "memberOf -RecursiveMatch '$((Get-ADGroup "Domain Admins").DistinguishedName)'" -SearchBase $((Get-ADUser Guest).DistinguishedName)

   Note We can use a Windows PowerShell variable subexpression $() to retrieve the user and group
   distinguished names dynamically and supply them to the filter properties.

Finally, we can make a handy function by adding a couple variables like this:

Function Test-ADGroupMember {

Param ($User,$Group)

  Trap {Return "error"}

  If (

    Get-ADUser `

      -Filter "memberOf -RecursiveMatch '$((Get-ADGroup $Group).DistinguishedName)'" `

      -SearchBase $((Get-ADUser $User).DistinguishedName)

    ) {$true}

    Else {$false}

}

Now we have a simple function to check if a user is nested into a privileged group:

PS C:\> Test-ADGroupMember -User Guest -Group "Domain Admins"

True

PS C:\> Test-ADGroupMember -User JoeJrAdmin -Group "Domain Admins"

False

PS C:\> Test-ADGroupMember -User bogus -Group "Domain Admins"

error

Uh oh! How did the Guest account get nested into Domain Admins? For that answer, you’ll need to read my post, AD Group History Mystery: PowerShell v3 REPADMIN.

This function performs three queries, so it is not very efficient. If you wanted to process a large number of users, you could try this approach instead:

$Group = "Domain Admins"

$Users = (Get-ADUser -Filter "name -like 'ad*'").DistinguishedName

$Members = (Get-ADGroupMember $Group -Recursive).DistinguishedName

ForEach ($User in $Users) {

  [PSCustomObject]@{

    User = $User

    Group = $Group

    IsMember = $Members.Contains($User)

  }

}

Adjust the Get-ADUser -Filter parameter to suit your needs. The output looks similar to this:

User                       Group     IsMember

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

CN=adbarr,OU=Migrated,DC=CohoVineyard,DC=com   Domain Admins  False

CN=adcarter,CN=Users,DC=CohoVineyard,DC=com   Domain Admins  False

CN=addumitr,CN=Users,DC=CohoVineyard,DC=com   Domain Admins  False

CN=Administrator,CN=Users,DC=CohoVineyard,DC=com Domain Admins   True

This table conveniently summarizes the techniques we have discussed in this blog post.

 

Immediate

Nested/Recursive

Members of a Group

Get-ADGroupMember GroupName

Get‑ADGroupMember GroupName‑Recursive

Group membership of a User

Get-ADPrincipalGroupMembership UserName

All groups:

Reference blog post:
Token Bloat Troubleshooting by Analyzing Group Nesting in AD

Test for one group:

Get-ADUser ‑Filter 'memberOf ‑RecursiveMatch "<distinguished name of group>"' ‑SearchBase "<distinguished name of user>"

Armed with this knowledge, you now have some scripting tools to help you trace group memberships.

~ Ashley

Thanks for this great series, Ashley! Come back tomorrow for Day 3 of Active Directory Week.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Use PowerShell to Find if User Is Nested Group Member

$
0
0

Summary: Use Windows PowerShell to find if a user is a nested member of a particular group.

Hey, Scripting Guy! Question How can I use Windows PowerShell to quickly find if a user is a nested member of a particular group,
           for example, Domain Admins?

Hey, Scripting Guy! Answer Use the -RecursiveMatch LDAP filter operator:

Get-ADUser -Filter 'memberOf ‑RecursiveMatch "CN=Administrators,CN=Builtin,DC=Fabrikam,DC=com"' ‑SearchBase "CN=Administrator,CN=Users,DC=Fabrikam,DC=com"

If the user is a member of the group, the query returns an AD object representing the user.
If not a member of the group, the query returns nothing.

You can even use it in a function:

Function Test-ADGroupMember {

Param ($User,$Group)

  Trap {Return "error"}

  If (

    Get-ADUser `

      -Filter "memberOf -RecursiveMatch '$((Get-ADGroup $Group).DistinguishedName)'" `

      -SearchBase $((Get-ADUser $User).DistinguishedName)

    ) {$true}

    Else {$false}

}

Now we have a simple function to check if a user is nested into a privileged group:

PS C:\> Test-ADGroupMember -User Guest -Group "Domain Admins"

True

PS C:\> Test-ADGroupMember -User JoeJrAdmin -Group "Domain Admins"

False

PS C:\> Test-ADGroupMember -User bogus -Group "Domain Admins"

error

 


Active Directory Week: Stale Object Cleanup Guidance—Part 1

$
0
0

Summary: Learn about how to clean up stale Active Directory accounts.

Microsoft Scripting Guy, Ed Wilson, is here. Today we continue our series about Active Directory PowerShell by Ashley McGlone. Before you begin, you might enjoy reading his first two posts:

Here's Ashley...

In the United States, this week we celebrate Thanksgiving. I’ve made the joke before that you can give thanks for Windows PowerShell, but your family really will not understand the significance. Nevertheless, I am thankful for family, friends, and Windows PowerShell.

Clean your room much?

In my work with Microsoft, I have found organizations with tens-of-thousands of stale user and computer accounts. Some companies never touch them. Others are surprised to find terminated users in the Domain Admins account. Only a few sincerely review and clean up stale accounts. How is this possible?

As a child, I remember my mother telling me to clean my room. And why did she have to tell me? Because most of us do not like to clean. My desk looks much like this these days! 

Photo of desk

I muster the time and courage to clean my officemaybe twice a year—and that is only when the pain of the paper piles exceeds my proclivity for procrastination. Active Directory is no different. Many businesses do not prioritize cleaning up stale accounts because there is no pain or penalty associated with it. That is until compliance audit time. Many compliance standards today mandate removal of stale accounts. Suddenly it becomes the "flavor of the month" with management when the auditors roll in.

Steps to stale account cleanup

So what are the steps to finding and removing stale accounts? I am glad you asked.

We would like it to be a simple query and delete. However, there is a little more to the story. It is fun to automate the process, but we need to think it through first. I would outline the process as follows:

1. Step one is to turn on the Active Directory Recycle Bin if not already enabled. This will be your safety net for accidental deletion of good accounts.

2. Identify your compliance timeframe for inactive accounts. 30 days? 90 days? This will likely be a conversation with the compliance project manager. Note that computers and managed service accounts reset their own passwords every 30 days. User accounts will depend on the domain password policy (Get‑ADDefaultDomainPasswordPolicy) and any fine-grained password policy (Get‑ADUserResultantPasswordPolicy).

3. Query the directory to find stale objects. Do not delete them yet! Criteria might include a ping response, DNS lookup result, PwdLastSet, or LastLogonTimestamp.

4. Review the data and create a list of known exceptions (for example, krbtgt user, key service accounts, high profile business users, or cluster computers. For more information about cluster computers, see Cluster and Stale Computer Accounts).

5. Script your cleanup process. I recommend two phases to each run once per week:

  • Phase 1. Disable stale accounts and append a notice to the account description, similar to this: Account disabled due to inactivity on 11/12/2014. Your exception list should be filtered prior to disabling accounts. First disabling the account makes recovery quick if someone calls to report that an account is actually active. Those accounts will then go on the exception list.
  • Phase 2. Query for the now disabled accounts that still have not been touched in 30 days. Filter again against the exception list. These should now be safe for removal. Deleting these accounts will send them to the Recycle Bin. If someone calls at this point, you can use Restore‑ADObject or the Active Directory Administrative Center (ADAC) graphical interface to restore the accounts. For computer accounts, you can optionally delete any DNS records and/or DHCP reservations.

6. Make sure that your scripts generate central log files and that your first-tier support team can review these when they are troubleshooting account issues.

7. Document the procedures for enabling or recovering a stale account that was incorrectly targeted. Also document the process for updating the exception list. Communicate these steps to your level-one support team. On second thought, maybe InfoSec should be the only ones granting exceptions. Sounds like a decision for the project manager.

8. After a few manual runs of the process, and when you feel comfortable with it, schedule these two phases to run weekly.

9. Monitor the logs and call volume closely for another 90 days. If necessary, adjust the process to eliminate false positives.

10. Report compliance status to management at each phase of the implementation and at regular intervals going forward. This can also be scripted with the Send-MailMessage cmdlet.

You may be able to add your own considerations to what I have listed.

Where's the Windows PowerShell?

Yes. This is a Windows PowerShell blog. The first step to writing any script is to properly scope the activity and define the outcome. I have provided a good outline for you to start. Now take this outline and adjust it to your specific needs.

And that is what we call a “cliff hanger.” Stay tuned. Tomorrow I'll present some scripting tips to jump start your stale account cleanup.

~ Ashley

(photo credit: camknows via photopincc)

Thanks again, Ashley! Ashley recently recorded a full day of free Active Directory PowerShell training: Microsoft Virtual Academy: Using PowerShell for Active Directory. Watch these videos to learn more insider tips on topics like getting started with Active Directory PowerShell, routine administration, stale accounts, managing replication, disaster recovery, and domain controller deployment.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Use PowerShell to Get Inactive Active Directory Accounts

$
0
0

Summary: Use Windows PowerShell to get a report of inactive Active Directory accounts.

Hey, Scripting Guy! QuestionHow can I use Windows PowerShell to get a report of inactive Active Directory accounts?

Hey, Scripting Guy! AnswerThe Search-ADAccount cmdlet has a number of parameters and switches to help identify stale accounts:

      • Search-ADAccount -AccountInactive
      • Search-ADAccount -AccountDisabled
      • Search-ADAccount -AccountExpired

You can also use the -UsersOnly or -ComputersOnly switch to narrow the results:

      • Search-ADAccount -AccountInactive -UsersOnly
      • Search-ADAccount -AccountInactive –ComputersOnly

 

Active Directory Week: Stale Object Cleanup Guidance—Part 2

$
0
0

Summary: Scripting tips for cleaning up stale Active Directory accounts.

Microsoft Scripting Guy, Ed Wilson, is here. Today we continue our series about Active Directory PowerShell by Ashley McGlone. Before you begin, you might enjoy reading these posts from the series:

See yesterday’s post for a discussion and guidance about stale-object cleanup. You really need to read it for context.

Continuing from yesterday…

I have been doing Active Directory scripting for well over a decade. You need to know that there is no fail-safe way to identify stale users and groups with 100% accuracy. We can have a high degree of certainty; but ultimately, there could be an odd case where the account has a dependency in the environment.

Do not over emphasize this point with management, but they need to know that there is a slight degree of risk. This minor risk factor turns off many departments from implementing the stale account cleanup.

Our goal is to eliminate as much risk as possible and offer the quickest recovery time should the wrong account get “cleaned.” Therefore, we must use multiple account properties to determine if accounts are still in use. Also refer to the safety steps in yesterday’s post.

It would not be practical for me to script the entire process for you in this post. But I do want to offer some scripting tips for identifying stale objects. This primarily involves the date fields in Active Directory and a few syntax nuances.

Which date do I query?

There are many date/time stamp and activity attributes in Active Directory accounts. Here are some of the most popular ones and a description of each. There are pros and cons to consider for most of these.

  • WhenCreated
    Date and time that the account was created. Compare with a modified date to see if it was ever actually used.
  • WhenModified
    Great property to see the last change date of an account. However, this property is not replicated and must be queried from every domain controller to be truly accurate.
  • LastLogon
    Date and time of the last logon. However, this property is not replicated. Use LastLogonTimestamp instead.
    For more information, see “The LastLogonTimeStamp Attribute”–What it was designed for and how it works.
  • LastLogonTimestamp
    Date and time of last logon. This is replicated to all domain controllers and a generally reliable measure.
    For more information, see “The LastLogonTimeStamp Attribute”–What it was designed for and how it works.
  • LogonCount
    Count of logons against each domain controller. However, this property is not replicated, and it must be queried from every domain controller to be truly accurate.
  • PwdLastSet
    Equal to zero or 9223372036854775807 if the password has never been set. This is generally a reliable way to gauge account usage—except for accounts with passwords that never expire. This number is actually a date/time value represented as an Int64 data type.
  • msDS-LastSuccessfulInteractiveLogonTime
    This attribute is only updated when a particular Group Policy setting is enabled. That policy is not practical for some environments, so this field is not as useful as it sounds initially.
    For more information, see this Question and Answer on the Ask the Directory Services Team blog.

Image of command output

There are many more attributes to explore. For some super-secret details about these attributes, I highly recommend checking out User Security Attributes.

Dates or numbers?

After you have picked the date fields, the next challenge is working with the date values. There are normal date/time data-type fields, and then there are "those" dates. You know—the dates that look like a long string of numbers. Whatever are we going to do with those?

We can use a couple methods to convert to and from that gnarly date format:

# Password last set within the last 30 days?

$pwdLastSet = Get-ADUser Administrator -Properties pwdLastSet |

     Select-Object -ExpandProperty pwdLastSet

# Option A

$pwdLastSet -gt (Get-Date).AddDays(-30).ToFileTimeUTC()

# Option B

[datetime]::fromFileTimeUTC($pwdLastSet) -gt (Get-Date).AddDays(-30)

For more details, see Back To The Future: Working with date data types in Active Directory PowerShell.

Documentation in the description

Modifying the account description may not be intuitive, so let's take a quick look at Set-ADObject. To append your staleness comment, try something like this:

Get-ADUser JoeUser -Properties Description |

    ForEach {Set-ADUser -Identity $_.DistinguishedName `

         -Replace @{Description = $_.Description + " *** Disabled as stale " + `

         (Get-Date -Format g)}}

Quick Windows PowerShell reports

There are some commands that will quickly show you inactive accounts:

### USERS ###

# Quick inactivity report

Search-ADAccount -AccountInactive -UsersOnly

# Timespan

Search-ADAccount -AccountInactive -UsersOnly -TimeSpan (New-TimeSpan -Days 90)

# Datetime

Search-ADAccount -AccountInactive -UsersOnly -DateTime '10/1/2014'

# Disabled

Search-ADAccount -AccountDisabled -UsersOnly

# Expired

Search-ADAccount -AccountExpired -UsersOnly

 

### COMPUTERS ###

# Quick inactivity report

Search-ADAccount -AccountInactive -ComputersOnly

# Timespan

Search-ADAccount -AccountInactive -ComputersOnly -TimeSpan (New-TimeSpan -Days 90)

# Datetime

Search-ADAccount -AccountInactive -ComputersOnly -DateTime '10/1/2014'

# Disabled

Search-ADAccount -AccountDisabled -ComputersOnly

These commands will return a list of user or computer accounts that you can filter against the exception list you created. For more information about Search-ADAccount cmdlets, see this Question and Answer on the Ask the Directory Services Team blog.

Then you can use Test-Connection to see if they respond to a ping (although this is not always reliable either). Use Resolve-DNSName for computers to see if they are still listed in DNS, assuming that you scavenge stale DNS records.

Wrapping up

I realize that these two posts do not offer a complete, scripted solution. However, you now have an expert design and code samples to begin your solution as you learn Windows PowerShell for Active Directory.

Stale account cleanup is a popular topic, and you can find many people who have attempted and published their scripts. You can use these as a place to start your script, or you can write it from scratch. Script resources for IT professionals in the Script Center Repository is a great place to start looking. (Of course any time you download a script from the Internet, you should read it thoroughly and test it in your lab first.)

After reviewing these considerations, it is easy to see why some people avoid the task. There is some fuzzy logic involved, a decent amount of coding, and a small degree of risk. Leverage online resources to help you through the process. If you get completely stuck, talk to your Microsoft premier services technical account manager. They can set up a call for you to talk through your challenges with a premier field engineer like me. You can also post questions to the Script Center Forums. Happy scripting!

~ Ashley

Thanks, Ashley! This is a very helpful series. Come back tomorrow for the final post of Ashley's Active Directory Week series.

Ashley recently recorded a full day of free Active Directory PowerShell training: Microsoft Virtual Academy: Using PowerShell for Active Directory. Watch these videos to learn more insider tips on topics like getting started with Active Directory PowerShell, routine administration, stale accounts, managing replication, disaster recovery, and domain controller deployment.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Windows PowerShell, Scripting Guy!, Guest blogger, Ashley McGlone, Active Directory

PowerTip: Use PowerShell to Work with Active Directory Date Fields

$
0
0

Summary: Use Windows PowerShell to work with Active Directory date fields.

Hey, Scripting Guy! Question How can I Use Windows PowerShell to work with date fields in Active Directory?

Hey, Scripting Guy! Answer Try the following techniques:

# Password last set within the last 30 days?

$pwdLastSet = Get-ADUser Administrator -Properties pwdLastSet |

     Select-Object -ExpandProperty pwdLastSet

# Option A

$pwdLastSet -gt (Get-Date).AddDays(-30).ToFileTimeUTC()

# Option B

[datetime]::fromFileTimeUTC($pwdLastSet) -gt (Get-Date).AddDays(-30)

 

Active Directory Week: Essential Steps for PowerShell when Upgrading

$
0
0

Summary: Learn three essential steps for Windows PowerShell when upgrading from Windows Server 2003.

Microsoft Scripting Guy, Ed Wilson, is here. Today we have the final post in the series about Active Directory PowerShell by Ashley McGlone. Before you begin, you might enjoy reading these posts from the series:

Over the years Microsoft has released a number of new features to enhance Active Directory functionality. (For more information, see Active Directory Features in Different Versions of Windows Server.) If you are just now upgrading from Windows Server 2003, you have much to be thankful for. You will get to use new features like the Active Directory Recycle Bin and “Protect from accidental deletion.” But first you must raise the forest functional level to at least Windows Server 2008 R2. Let’s look at how to turn on these features.

Raise the functional level

In the Windows Server 2008 R2 era, many new Active Directory features were dependent on domain or forest functional level. One significant change with Windows Server 2012 R2 and Windows Server 2012 is that the product group tried to reduce the dependency on functional level for new features. At a minimum, you want to move your forest functional level to the Windows Server 2008 R2. You can raise it to Windows Server 2012 R2 if all of your domain controllers are on the current release.

Of course, these steps can be done in the graphical interface, but this post is about Windows PowerShell. It is actually quite easy to do from the Windows PowerShell console. First, let’s check the current functional modes:

PS C:\> (Get-ADDomain).DomainMode

PS C:\> (Get-ADForest).ForestMode

   Note  If you are running these commands on Windows Server 2008 R2, you must first run this line:

Import-Module ActiveDirectory

DomainMode and ForestMode are properties of the ADDomain and ADForest, respectively. Lucky for us there is a cmdlet to set each of these. Look at this syntax:

$domain = Get-ADDomain

Set-ADDomainMode -Identity $domain -Server $domain.PDCEmulator -DomainMode Windows2012Domain

$forest = Get-ADForest

Set-ADForestMode -Identity $forest -Server $forest.SchemaMaster -ForestMode Windows2012Forest

   Note  You must target the PDC Emulator for domain mode changes and the Schema Master for forest mode changes.

The following table shows the available domain and forest mode parameter values:

Set-ADDomainMode

Set-ADForestMode

Win2003Domain

Win2008Domain

Win2008R2Domain

Win2012Domain

Win2012R2Domain

Windows2000Forest

Windows2003InterimForest

Windows2003Forest

Windows2008Forest

Windows2008R2Forest

Windows2012Forest

Windows2012R2Forest

Here are some points to consider:

  • If you raise the forest functional level, it will automatically attempt to raise the level of all the domains first.
  • Generally, these commands only raise functional level. You cannot lower the level. (There is a minor exception, which is documented in How to Revert Back or Lower the Active Directory Forest and Domain Functional Levels in Windows Server 2008 R2.)
  • All domain controllers must be at the same or higher operating system level as the functional mode.
  • Be sure that you have a good backup of the forest for any possible recovery scenario afterward.

For more information about raising functional level, see What is the Impact of Upgrading the Domain or Forest Functional Level?

Enable the Active Directory Recycle Bin

Hopefully, this feature is old news to you by now. The key point is that it is not automatic. You must enable the Active Directory Recycle Bin before you can restore a deleted account. Here is the easiest way to enable the Active Directory  Recycle Bin from Windows PowerShell:

Enable-ADOptionalFeature 'Recycle Bin Feature' -Scope ForestOrConfigurationSet `

    -Target (Get-ADForest).RootDomain -Server (Get-ADForest).DomainNamingMaster

This command is written so that it will work in any environment. Note that it must target the forest Domain Naming Master role holder.

For more information and potential troubleshooting steps, see:

Now you can use the Restore-ADObject cmdlet or the Active Directory Administrative Center (ADAC) graphical interface to recover deleted objects. This is so much easier than an Active Directory authoritative restore!

Protect from accidental deletion

Have you noticed a theme yet? “Recycle bin” and “accidental deletion”...

We want to help you recover faster. The “Protect from accidental deletion” feature will hopefully keep you from needing the Recycle Bin. The following image shows the check box for the setting in the graphical interface:

Image of menu

With the Active Directory cmdlets, we can find the status by using the ProtectedFromAccidentalDeletion object property like this:

Get-ADuser ProtectMe -Properties ProtectedFromAccidentalDeletion

This value will be True or False, depending on whether the box is selected. To turn on the protection, we can use this syntax:

Get-ADUser -Identity ProtectMe | Set-ADObject -ProtectedFromAccidentalDeletion:$true

It would be inefficient to do this one-at-a-time for all objects, wouldn’t it? Here are some commands you could use to turn it on more broadly across your environment:

Get-ADUser -Filter * | Set-ADObject -ProtectedFromAccidentalDeletion:$true

Get-ADGroup -Filter * | Set-ADObject -ProtectedFromAccidentalDeletion:$true

Get-ADOrganizationalUnit -Filter * | Set-ADObject -ProtectedFromAccidentalDeletion:$true

The next logical question would be, “OK. Then how do I delete something when it is not an accident?”

I am glad you asked. We can turn off the protection and delete an object like this:

Get-ADUser ProtectMe |

    Set-ADObject -ProtectedFromAccidentalDeletion:$false -PassThru |

    Remove-ADUser -Confirm:$false

Notice that we use the -PassThru switch to keep the user object moving through the pipeline after the Set command.

This delete protection is not enabled by default. It must be explicitly set on each object that you want to protect. For information about how to make this automatic for new objects, you can read the comments that follow this post on the Ask the Directory Services Team blog: Two lines that can save your AD from a crisis.

Note  If you would like to know more about how this feature works, we explain this topic in greater detail in Module 7 of the Microsoft Virtual Academy videos, Active Directory Attribute Recovery With PowerShell.

Bonus tips

In this post, we discussed three essentials steps when upgrading from Windows Server 2003:

  1. Raise the domain and forest functional level
  2. Enable Recycle Bin
  3. Protect from accidental deletion

Of course, there are many other new features to leverage. I recommend that you check out the following resources in the Microsoft Virtual Academy videos:

  • In Module 7, we discuss a recovery strategy that uses Active Directory snapshots. This is a friendly way to recover corrupted Active Directory properties without the hassle of a full authoritative restoration. I recommend that all customers start taking Active Directory snapshots (not to be confused with virtual machine snapshots) on a regular basis to aid in the recovery process.
  • In Module 8, we discuss three tips to help you deploy domain controllers faster during your upgrade. Note that DCPROMO was depreciated in Windows Server 2012 R2.

In addition, you should consider migrating SYSVOL from NTFRS to DFSR replication. This is another benefit after the functional level change, and it requires a manual step to turn it on. This is not addressed in the videos, but these steps are documented on TechNet and in a number of blog posts. For example, see, SYSVOL Replication Migration Guide: FRS to DFS Replication.

Congratulations on your move from Windows Server 2003! You will find that the later operating systems have many more features and tools to help with routine administration, maintenance, and security. With the tips from this post, you have a jumpstart for automating new features to aid in recovery scenarios.

Watch my free training videos for Active Directory PowerShell on Microsoft Virtual Academy to learn more insider tips on topics such as getting started with Active Directory PowerShell, routine administration, stale accounts, managing replication, disaster recovery, domain controller deployment.

~Ashley

And that ends our series about Active Directory PowerShell by Ashley McGlone! Join me tomorrow when I seek a way to find the latitude and longitude for a specific address.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Use PowerShell to Get List of FSMO Role Holders

$
0
0

Summary: Use Windows PowerShell to get a list of FSMO role holders in Active Directory.

Hey, Scripting Guy! Question I use NETDOM QUERY FSMO to list my domain controllers that hold the FSMO roles, but can I do it with Windows PowerShell?

Hey, Scripting Guy! Answer As usual, there is more than one way to do most things in Windows PowerShell, but here are some syntax examples to meet your needs:

Get-ADDomain | Select-Object InfrastructureMaster, RIDMaster, PDCEmulator

Get-ADForest | Select-Object DomainNamingMaster, SchemaMaster

Get-ADDomainController -Filter * |

     Select-Object Name, Domain, Forest, OperationMasterRoles |

     Where-Object {$_.OperationMasterRoles} |

     Format-Table -AutoSize

 

Weekend Scripter: Latitude, Longitude, and PowerShell

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to retrieve latitude and longitude information.

Microsoft Scripting Guy, Ed Wilson, is here. Today it is cold and dreary, so I thought it would be a nice time to play around with Windows PowerShell. One of the things I have always wanted to do is use Windows PowerShell to find the latitude and longitude for a specific address. I know there are webpages where I can look up this information—but if I ever want to do anything with latitude and longitude in a Windows PowerShell script, I had better know how to do the lookup.

So, I started hunting around for an easy-to-use web service. I found one. Well, it is not really easy-to-use, but it does have the benefit of being free. The disadvantage is that I have to provide an almost complete address. At a minimum, it requires the street address, city, and state. Also, I believe it only works for addresses in the United States, which basically leaves out over half of my readers.

Another disadvantage is the way I have to encode the question into a string. This becomes more or less a manual process. I tried to use the URLEncode method from the WebUtility class, but all that did was really munge things. I wish I could provide only a city, state, and country and get a generic latitude and longitude. I also wish there was a better way to supply these values instead of having to encode them in a string.

I will admit that I have not spent all day playing with this service, nor have I spent more than about a half hour searching for a better web service. If you find something better, let me know. I did find that Google has a pretty good API for this, but the terms say it is for displaying on a Google map, which is not what I want to do.

After I have a latitude and longitude, there are many cool things I can do. For instance, I now have a GPS receiver for my camera that writes latitude and longitude on my pictures. But before that I did not, so I could get a latitude and longitude for a specific location, and then write that information to all of my pictures in a specific folder (which are sorted by location anyway).

I can also look up weather, sunrise, and sunset information. And I can do a reverse lookup—so I can look up an address based on the latitude and longitude from a picture I have.

The hard parts about using this web service are encoding the address and finding a specific address that it is able to resolve. For example, it could not find my house in Charlotte, North Carolina in the United States. But it was able to find the White House (not in Charlotte, of course).

The first thing I need to do is to create a string that indicates the interface I want to use and the address. The address is separated by street, city, and state. When I come to a space, I use a plus sign ( + ). I am using an interface that returns the information as comma-separated values. Other interfaces are available by checking the geocoder.us website. Here is my string:

$uri = 'http://rpc.geocoder.us/service/csv?address=1+Times+Square,+New+York+NY'

Now I use the Invoke-RestMethod cmdlet, specify that I am using the Getmethod, and capture my results in a variable:

$csv = Invoke-RestMethod -Method Get -Uri $uri

The contents of the $csv variable are shown here:

PS C:\> $csv

40.756639,-73.986287,1 Times Sq,New York,NY,10036

The results are: Latitude, Longitude, Street, City, State, and Zip code. Obviously, I already know the street, city, and state because that is what I supplied to the call. So I can capture the first and second elements. I do this by using the Splitmethod to split my string at the comma. I then store the results in variables. The first element (0) contains my latitude, and the second element (1) contains the longitude. This is shown here:

$lat = ($csv -split ',')[0]

$long = ($csv -split ',')[1]

So that is it. Here is the complete script:

$uri = 'http://rpc.geocoder.us/service/csv?address=1+Times+Square,+New+York+NY'

$csv = Invoke-RestMethod -Method Get -Uri $uri

$lat = ($csv -split ',')[0]

$long = ($csv -split ',')[1]

$lat, $long

The script and the output from the script are shown in the following image:

Image of command output

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 


PowerTip: Find Module Information from Cmdlet

$
0
0

Summary: Find Windows PowerShell module information from a cmdlet.

Hey, Scripting Guy! Question How can I find more information about the module that provides a Windows PowerShell cmdlet?

Hey, Scripting Guy! Answer Use the Get-Command cmdlet, pipe the results to the Foreach-Object cmdlet, then inside the script block,
           use Get-Module. Here is an example using the Get-Process cmdlet:

Get-Command get-process | foreach {Get-Module -name $_.modulename}

Networking Ideas for PowerShell Scripters

$
0
0

Summary: The Scripting Wife presents networking ideas for Windows PowerShell scripters.

Microsoft Scripting Guy, Ed Wilson, is here. Today the Scripting Wife is going to write the blog post...

Hello fellow scripters!

The Scripting Guy, Ed Wilson, is not feeling so great, so I thought I would be nice to him on this Sunday morning and write this blog post. If you are new to this blog, I am Ed’s real-life wife and a Microsoft MVP. To read more of my posts, see these Hey, Scripting Guy! Blog posts

November has been an exciting and busy month for me personally. It started with the MVP Summit and ended with the Thanksgiving holiday weekend. I flew into SeaTac airport a few days early for the MVP Summit so I could spend some time there with virtual friends who I have interacted with via a Facebook group. I stayed at this cottage a bit north of Seattle, and I had a marvelous time. There is a point to my story...

The Internet and social media are loaded with lots of useful information. I have two loves besides Microsoft and Windows PowerShell. One is horses and the other is reading. Through a Facebook group page, I met like-minded friends who love the Friesian breed of horses. To be able to follow-up with them for a real-life visit 3000 miles away was quite an experience.

There are also great places to access on the Internet for Windows PowerShell fans. The Facebook group pages I think you will be most interested in are The Scripting Guys and PowerShell. Here are a few other pages that you might enjoy: PowerShell.org, PowerShell Magazine, and the PowerScripting Podcast.

Speaking of social media, do not forget about Twitter. There are so many useful items there, such as links to blog posts and user group meetings.

Another valuable resource for Windows PowerShell users is the forums. The top two that I am familiar with are The Script Center and the Powershell.org Forums. On a forum site, you can read questions and answers, you can ask questions, and you can answer questions to help others who are stuck.

Hope you have a great day.

~Teresa

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace. 

Ed Wilson, Microsoft Scripting Guy

 

Provide Support by Using Verbose and Debug Streams

$
0
0

SummaryProvide code support by using Verbose and Debug streams.

Honorary Scripting Guy and Windows PowerShell MVP, Boe Prox, here today filling in for my good friend, The Scripting Guy. This is the first part in a series of five posts about troubleshooting Windows PowerShell scripts and functions. The series includes:

  1. Provide Support by Using Verbose and Debug Streams (this post)
  2. Troubleshoot by Using Set-PSDebug
  3. Enforce Better Script Practices by Using Set-StrictMode
  4. Trace Your Commands by Using Trace-Command
  5. Use the PowerShell Debugger

When you write a script or function, you want to make sure that things work correctly and that you have provided enough information for the individuals who will be using the code in their day-to-day activities. Although you have Get-Help and inline comments in the code, sometimes they don’t provide the kind of troubleshooting that is needed when you are not getting the results that you are expecting.

We need a way to provide on-screen information that can be turned on or off without much more than a simple parameter. If only we had some sort of Verbose or Debug capability that could make this happen…

Oh, wait!

We have this built-in with Windows PowerShell!

Whenever a script or function is being built, all we have to do is add a couple of lines at the beginning of the code block to enable the Verbose and Debug parameters. As shown here, those pieces are [cmdletbinding()] and Param():

[cmdletbinding()]

Param ()

Image of command output

You must have these attributes available to have this capability. After this is accomplished, you can use Write-Verbose and Write-Debug in your code to provide more information when the script runs. Of course, you could use Write-Host, but that doesn’t turn off unless you provide your own parameter (a switch) and then use some logic to run the command if the parameter is used.

Using Verbose and Debug provides a cleaner approach to providing output by having a single line (Write-Verbose or Write-Debug) that provides information to the users (or to yourself) when someone is attempting to figure out why a script isn’t running the way it should. Another great feature that was introduced in Windows PowerShell 3.0 is that you can redirect the streams to a file if needed.

Note  June Blender wrote an excellent post that you can read for more information: Understanding Streams, Redirection, and Write-Host in PowerShell.

So how should I use Write-Verbose and Write-Debug? In the end, it depends on what you want to use them for. In my case, I use them in the following ways:

  • Write-Verbose
    More for the user experience to show what is happening during the execution of the script.
  • Write-Debug
    More for the code writer to show various points in the code, such as variables and their current values, that I can use to troubleshoot issues.

Knowing what I need to do to use Verbose and Debug streams, I can add those to a function and give it a run to see what happens. The following function provides an example to show using Verbose and Debug:

Function Invoke-Action {

    [cmdletbinding()]

    Param (

        $Computername,

        [hashtable]$Options,

        $Timeout

    )   

    $PSBoundParameters.GetEnumerator() | ForEach {

        Write-Debug "[PSBoundParameters] $($_)"

    }

    If ($PSBoundParameters['Options']) {

        $Options.GetEnumerator() | ForEach {

            Write-Debug "[Options] $($_.Name) -> $($_.Value)"

        }

    }

    ForEach ($Computer in $Computername) {

        Write-Verbose "Testing $Computer"

    }

}

Running this with both the –Verbose and –Debug parameters will give us a couple of streams that we can use to help determine what is going on in the script when it is running. Notice that I do not have to specify –Verbose or –Debug when I use Write-Verbose and Write-Debug. I will have to specify these parameters when I call the function in order to see the desired results.

Invoke-Action -Computername 'Computer1','Computer2','Computer3' -Options @{SkipIfOffline=$True;TestIsAdmin=$False} -Timeout 100 -Verbose -Debug

Image of command output

As you can see in this image, I have Debug showing the values of my bound parameters and listing the values in my options parameter. When you use –Debug in the function, it automatically sets the $DebugPreference for the scope of the function to ‘Inquire’, which works by prompting for user interaction.

I opted to use Verbose to say what was happening with the action being performed in the script. I could do more with either of these parameters, such as adding a time stamp, which can make it easier to see when each action is happening. I could also add a line number so myself or someone else can know exactly where the action is taking place.

As mentioned earlier, it is my preference to use Debug and Verbose, and not everyone might share this approach. When you use these in your code to provide some sort of simple troubleshooting of a script, you really can’t go wrong. The idea is to provide an approach so that you or someone else using your script can track down a possible issue and hopefully resolve it.

That is all there is to using the Verbose and Debug streams in a script or function to provide a way to troubleshoot scripts. Tomorrow I will show you how to use the Set-PSDebug cmdlet to troubleshoot scripts.

We invite you to follow the Scripting Guy on Twitter and Facebook. If you have any questions, send email to the Scripting Guy at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. Until then, see ya!

Boe Prox, Windows PowerShell MVP and Honorary Scripting Guy 

PowerTip: Avoid Prompt When Using –Debug

$
0
0

Summary: Boe Prox shows how to avoid being prompted when using –Debug.

Hey, Scripting Guy! Question I love using –Debug in functions to figure out what is going on, but how can I avoid being prompted
           each time I run into Write-Debug in my code?

Hey, Scripting Guy! Answer After you declare your parameters, check for –Debug, and set the $DebugPreference 
           value to ‘Continue’ instead of ‘Inquire’:

If ($PSBoundParameters[‘Debug’]) {

    $DebugPreference='Continue'

}

Troubleshoot by Using Set-PSDebug

$
0
0

Summary: Boe Prox uses the Set-PSDebug cmdlet to assist in troubleshooting.

Honorary Scripting Guy and Windows PowerShell MVP, Boe Prox, here today filling in for my good friend, The Scripting Guy. This is the second part in a series of five posts about troubleshooting Windows PowerShell scripts and functions. The series includes:

  1. Provide Support by Using Verbose and Debug Streams
  2. Troubleshoot by Using Set-PSDebug (this post)
  3. Enforce Better Script Practices by Using Set-StrictMode
  4. Trace Your Commands by Using Trace-Command
  5. Use the PowerShell Debugger

Today I am going to talk about using the Set-PSDebug cmdlet to assist in troubleshooting a script or function. This cmdlet provides some basic debugging capabilities and allows you to set up trace levels, depending on how you want to view the execution of a script or function. This is nice when you do not want to put together a lot of debug lines in your code. Besides that, you can track whether you are correctly assigning values to variables by using StrictMode.

First let’s take a look at the parameters that are available with Set-PSDebug and see what we can work with:

Get-Help Set-PSDebug

Image of command output

We have two parameter sets, one that supports turning off the debugging and another that allows us to turn on Strict mode, set a trace level, and the option to step through each line of the statement in the code.

Turning on Strict mode allows us to ensure that we are defining variables in our code. For a quick example, we can run the following code:

1..10 | ForEach {

    $i++

}

$i

In this case (and assuming you have only run it once), the value of $i would be 10. The issue here is that we never actually defined the variable up front. Now let’s set up Strict mode by using Set-PSDebug and try this again to see what happens.

Remove-Variable i

Set-PSDebug -Strict

1..10 | ForEach {

    $i++

}

$i

The variable $i cannot be retrieved because it has not been set.

At line:6 char:1

+ $i

+ ~~

    + CategoryInfo          : InvalidOperation: (i:String) [], RuntimeExceptio

   n

    + FullyQualifiedErrorId : VariableIsUndefined

I removed the variable after my last example to show that if you attempt to increment the variable before assigning it, it will throw an error message (in this case, up to 10) stating that the variable has not yet been defined. This is pretty useful if you want to make sure that you have defined all of your variables in your script or function.

I do not want to keep Strict mode enabled, so I will turn it off:

Set-PSDebug –Off

This not only turns off the Strict mode, but it will also turn off the other enabled properties, such as the trace level and stepping through each statement.

That was pretty cool. But now let’s dive into my favorite part about using Set-PSDebug: trace levels! This is where we can really see what is happening during the execution of the code. With Trace, we have the following options:

 0

 Turn off script tracing.

 1

 Traces each line of code that is being executed. Non-executed lines are not displayed.

 2

 Traces each line of code that is being executed. Non-executed lines are not displayed.
 Displays variable assignments and calls to other functions and script blocks.

We already can tell that setting the trace level to 0 turns it off, so there really is no need to demo that piece. Instead, we will go into the first level, 1, and see what happens with the code when it is executed:

Set-PSDebug –Trace 1

Now let’s run some code to see what is displayed in the console.

## Traces

Function Test {

    Param (

        [int]$Value

    )

    $Value++

    Write-Output $Value

}

Set-PSDebug -Trace 1

 

[int]$z=0

$Return = $Null

Get-ChildItem | Select -First 5 | ForEach {   

    If ($_.name -match '^p') {

        $File = $_

        $Return += ("{0} [{1}]`r`n" -f $File,(Test ($z++)))

    }

}

$Return

Image of command output

The trace level has been set to 1, meaning that only the lines that are executed will be displayed on the console. With that, we can see each iteration of Get-ChildItem and sometimes we have calls to the Test function, which increments a counter before finally displaying the files we are expecting.

Pretty cool stuff! Now let’s up the trace level to 2 and see the output!

Set-PSDebug -Trace 2

[int]$z=0

$Return = $Null

Get-ChildItem | Select -First 5 | ForEach {   

    If ($_.name -match '^p') {

        $File = $_

        $Return += ("{0} [{1}]`r`n" -f $File,(Test ($z++)))

    }

}

$Return

Image of command output

We see that variable assignments are now displayed on the console along with calls to functions and script blocks. The variable assignments really help to determine if the script is functioning the way it should.

That is all there is to using Set-PSDebug to help with troubleshooting scripts. Join me tomorrow when I discuss using Set-StrictMode. 

We invite you to follow the Scripting Guy on Twitter and Facebook. If you have any questions, send email to the Scripting Guy at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. Until then, see ya!

Boe Prox, Windows PowerShell MVP and Honorary Scripting Guy 

Viewing all 3333 articles
Browse latest View live




Latest Images