Quantcast
Channel: GoateePFE
Viewing all 28 articles
Browse latest View live

PowerShell: SID Walker, Texas Ranger (Part 1)

$
0
0

SID Walker

First things first:

  1. If Chuck Norris wrote a PowerShell script it would be a one-liner, because Chuck Norris can do anything in one strike.
  2. Chuck Norris does not have SID history, because there is only one Chuck Norris.
  3. Chuck Norris' ACL only has one ACE: Chuck Norris – Full Control.

Do you remember SIDWALK?  This resource kit utility was written back in the NT 4.0 days to assist with domain migrations.  It used a mapping file to rewrite old SIDs with new SIDs across ACLs in a number of areas:  files shares, printer shares, registry paths, NTFS permissions, etc.  That utility is a teenager now (born 1998).  It's time we rewrite this and bring it up to date… in PowerShell.

Sidwalk V1.0
Copyright (C) 1998 Microsoft Corporation
Usage: Sidwalk <profile file> [<profile file> ..] [/t /f [<path>] /r /s /p /g /l <file>]

In part one of this series we will learn how to parse SIDs out of SDDL that we receive from Get-ACL.  This handy cmdlet works with many of these permissions.  Once we get the SIDs parsed out of SDDL, a future post will walk us through swapping them out and updating them.

Why SID Walker?  Why PowerShell?

One of my favorite Active Directory topics is SID history and its impact on token size.  In my former post I discussed creating a SID mapping file by querying SID history data from AD.  Eventually I plan to release a PowerShell module for remediating token size issues due to SID history.  This series on SID translation will be the centerpiece of that module.

Whether you are doing a domain migration, cleaning up SID history, or doing a search-and-replace for a group migration project this script will become your BFF.

Terms of Security

Most of us already know these terms, but let me define a few of these up front for anyone who is not familiar with them:

  • ACLAccess Control List– This is the list of permissions on a resource (file, folder, registry key, etc.).  ACLs contain ACEs.
  • ACEAccess Control Entry– This is an individual permission entry on an ACL.  An example would be TEXAS\cnorris Allow FullControl.
  • SDDLSecurity Descriptor Definition Language– This is a short-hand string that represents the entire ACL in a single, encoded string.  See MSDN for the specifics.
  • SIDSecurity Identifier– This is the unique security GUID that is assign to all security principles in a domain (users, computers, groups).  SIDs live in ACEs to represent the users who get the access.

Get-ACL

Editing ACLs with VBScript was a royal pain, but now we have the Get-ACL and Set-ACL cmdlets in PowerShell.  Setting and getting permissions on the file system, registry, and even AD organizational units has become a one-liner.  Look at the sample output for Get-ACL below:

PS C:\Users\ashley> Get-ACL | gm

TypeName: System.Security.AccessControl.DirectorySecurity

Name            MemberType      Definition
----            ----------      ----------
Access          CodeProperty    System.Security.AccessControl.Auth...
Sddl            CodeProperty    System.String Sddl{get=GetSddl;}
AccessToString  ScriptProperty  System.Object AccessToString {get=...

<<output trimmed>>

 

PS C:\Users\ashley> Get-ACL | fl *


PSPath                  : Microsoft.PowerShell.Core\FileSystem::C:\Users\ashley
PSParentPath            : Microsoft.PowerShell.Core\FileSystem::C:\Users
PSChildName             : ashley
PSDrive                 : C
PSProvider              : Microsoft.PowerShell.Core\FileSystem
AccessToString          : NT AUTHORITY\SYSTEM Allow  FullControl
                          BUILTIN\Administrators Allow  FullControl
                          NADOMAIN\ashley Allow  FullControl
AuditToString           :
Path                    : Microsoft.PowerShell.Core\FileSystem::C:\Users\ashley
Owner                   : NT AUTHORITY\SYSTEM
Group                   : NT AUTHORITY\SYSTEM
Access                  : {System.Security.AccessControl.FileSystemAccessRule, System.Security.AccessControl.FileSystemAccessRule, System.Security.AccessControl.FileSystemAccessRule}
Sddl                    : O:SYG:SYD:P(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;FA;;;S-1-5-21-468525095-708123637-3513119021-43309)
AccessRightType         : System.Security.AccessControl.FileSystemRights
AccessRuleType          : System.Security.AccessControl.FileSystemAccessRule
AuditRuleType           : System.Security.AccessControl.FileSystemAuditRule
AreAccessRulesProtected : True
AreAuditRulesProtected  : False
AreAccessRulesCanonical : True
AreAuditRulesCanonical  : True

 

PS C:\Users\ashley> (Get-ACL).Access | fl *

FileSystemRights  : FullControl
AccessControlType : Allow
IdentityReference : NT AUTHORITY\SYSTEM
IsInherited       : False
InheritanceFlags  : ContainerInherit, ObjectInherit
PropagationFlags  : None

FileSystemRights  : FullControl
AccessControlType : Allow
IdentityReference : BUILTIN\Administrators
IsInherited       : False
InheritanceFlags  : ContainerInherit, ObjectInherit
PropagationFlags  : None

FileSystemRights  : FullControl
AccessControlType : Allow
IdentityReference : NORTHAMERICA\asmcglon
IsInherited       : False
InheritanceFlags  : ContainerInherit, ObjectInherit
PropagationFlags  : None

Get-ACL gives us the same ACL in three different properties:

  1. AccessToString– This is a simplified representation to get a summary of the ACEs.
  2. Access– This is an array of access rule objects with rich properties.  Enumerating these is the easiest way to script and report against ACLs.
  3. SDDL– This is the only place where you can see the actual SIDs behind the ACEs.  For our purposes of SID translation we'll have to use this property.

You can pass any file, registry, or OU path to Get-ACL.  Without the path it defaults to the local context.  See "Get-Help Get-ACL -Full" for more information.

SDDL

Although it looks cryptic, a few minutes of study on MSDN will help you crack the code and break down what is happening in the SDDL string.  Notice the string in the example below (note that the SID has been changed to protect the innocent):

O:SYG:SYD:P(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;FA;;;S-1-5-21-468525095-708123637-3513119021-43309)

Look what happens when we break it down by the parentheses:

  1. O:SYG:SYD:P
  2. (A;OICI;FA;;;SY)
  3. (A;OICI;FA;;;BA)
  4. (A;OICI;FA;;;S-1-5-21-468525095-708123637-3513119021-43309)

The first piece contains owner and primary group information.  We're going to skip this for now; SIDs can live here, but we are targeting ACEs specifically.  The next three pieces delimited in parentheses correspond to each of the three ACEs in the ACL.  Note that the last one contains a SID, because it references a non-default account in the ACE.

Now let's break down that last ACE.  Observe that ACEs are delimited with semicolons:

  1. A;
  2. OICI;
  3. FA;
  4. ;
  5. ;
  6. S-1-5-21-468525095-708123637-3513119021-43309

The "A" means "allow".  "OI" and "CI" reference "ObjectInherit" and "ContainerInherit" as observed in the full output of the Access property listed above.  These denote that permissions set at this level will be inherited downward.  If this value contained "ID", then we would know that the values where inherited from above and not explicitly defined at this level.  You can read about the other specific SDDL coding on MSDN.

The last element of the ACE array contains the SID, and that is our target for this script.  The user or group SID will always live in the 5th array index of each ACE.  If there is no SID here, then you'll find an alpha code representing a well-known group.

Finding SIDs in ACLs

To summarize our breakdown of SDDL above you can find the ACL SIDs using the process below:

  1. Get the ACL
  2. Get the SDDL string of the ACL
  3. Split the SDDL on parentheses to get the ACEs
  4. Split the ACEs on semicolons
  5. Reference the last index of the ACE array to find the SID

While this may seem like a lot of effort that is exactly what PowerShell does best.  We'll wrap this process into a function to reuse and call for each ACL that we want to parse.

Why all of this trouble?  Why not use the robust Access property array?  Remember that we are translating SIDs, and this is the only place where we can find them.  Both the regular account SID and the SID history will appear the same in the DOMAIN\username representation of the Access property ACE objects.  This is an important distinction.

The Code

The script attached to this blog gives you a basic function to parse SDDL as described above.  As an educational script it includes much verbose output and comments.  Study the output to learn more about how ACLs, ACEs, and SDDL work in different security contexts (file system vs. registry vs. AD).  Customize it for your own needs.  Note that we ignore any ACEs that are inherited, because we only want to target ACEs with explicit permissions for translation.

Coming Up Next

The next post in this series will adapt this function into a larger script that mimics SIDWALK by translating SIDs on file resources.  We'll learn how to unleash your inner Chuck Norris round house kick on SID history.

<#---------------------------------------------------------------------------
 Ashley McGlone, Microsoft PFE
http://blogs.technet.com/b/ashleymcglone
 August, 2011
 Parse-SDDL function.
http://msdn.microsoft.com/en-us/library/aa374928.aspx
 ace_type;ace_flags;rights;object_guid;inherit_object_guid;account_sid
 0 ;1 ;2 ;3 ;4 ;5
 0 ;ID ;2 ;3 ;4 ;SID
 Split the SDDL on the characer: (
 Process indexes 1 to end
 Split on character ;
 If index 1 contains "ID" then ignore because inherited
 If index 5 contains a SID then process it
---------------------------------------------------------------------------#>functionParse-SDDL{[CmdletBinding()]param([Parameter(valueFromPipelineByPropertyName=$true)]$SDDL)$SDDLSplit=$SDDL.Split("(")"`n---SDDL Split:"$SDDLSplit"`n---SDDL SID Parsing:"# Skip index 0 where owner and/or primary group are storedFor($i=1;$i-lt$SDDLSplit.Length;$i++){$ACLSplit=$SDDLSplit[$i].Split(";")If($ACLSplit[1].Contains("ID")){"Inherited"}Else{$ACLEntrySID=$null# Remove the trailing ")"$ACLEntry=$ACLSplit[5].TrimEnd(")")# Parse out the SID using a handy RegEx$ACLEntrySIDMatches=[regex]::Matches($ACLEntry,"(S(-\d+){2,8})")$ACLEntrySIDMatches|ForEach-Object{$ACLEntrySID=$_.value}If($ACLEntrySID){$ACLEntrySID}Else{"Not inherited - No SID"}}}#return $null}# Experiment with these different path values to see what the ACL objects do$path="C:\users\username\"#Not inherited$path="C:\users\username\desktop\"#Inherited$path="HKCU:\"#Not Inherited$path="HKCU:\Software"#Inherited$path="HKLM:\"#Not Inherited"`n---Path:"$Path$ACL=Get-ACL$path"`n---Access To String:"$ACL.AccessToString"`n---Access entry details:"$ACL.Access|fl*"`n---SDDL:"$ACL.SDDL# Call with named parameter binding$ACL|Parse-SDDL# Call with parameter string#Parse-SDDL $ACL.SDDL# ><>

PowerShell: SID Walker, Texas Ranger (Part 2)

$
0
0

More bad Chuck Norris one liners:

  1. You don't get access unless Chuck Norris says you get access.
  2. The Chuck Norris array starts and ends on 1, because Chuck Norris is never a zero.
  3. Chuck Norris' PowerShell console NEVER shows red text.

This is part two in a series on translating SIDs in ACLs.  Start by reading Part One if you haven't done so already.  Today we're going to unleash a Chuck Norris round house kick on old SIDs stinking up our file servers.  It's time to take out the trash.

The Scenario

In my former post on SID history I explained…

Tell me if this scenario has ever happened at your company. You are doing an AD migration with the ADMT (or a similar product). You migrated the users and groups. The project schedule was falling behind. You take a shortcut with the member servers. Instead of using the ADMT security translation process you just rejoin the servers to the new domain, leaving all of the old ACLs and SIDs untouched. You leave SID history in place and move on to the next big project and deadline.

The Requirements

We need a solution that will

  • Scan a file server
  • Find all of the NTFS permissions (ACLs)
  • Find the SIDs in those permissions (ACEs)
  • Compare each ACE SID to our SID history mapping file to see if it needs swapped
  • Swap the old SID with the new SID

An Added Twist… The NAS

The ADMT (Active Directory Migration Tool) is the ideal solution, well almost.  An added complexity here is that many companies migrate Windows file servers to a NAS (network attached storage).  The ADMT does security translation by deploying an agent that runs on Windows servers and translates all of the SIDs locally.  Since a NAS is not a Windows server, the ADMT is powerless to translate the SIDs stored there.  The security translation agent cannot run on a NAS.  I know what you're thinking, though.  "From a Windows server just map the NAS as a drive or mount it under a local folder.  Then the ADMT will see it."  That's what I thought, too.  We're both wrong.  After rereading the ADMT guide, trying a few work-arounds, and confirming this internally I have realized that the ADMT simply cannot work with a NAS.  (If you've done it I would love to hear your story.)

Then I turned to a host of utilities that have been around for years:  SIDWALK, SHOWACCS, SUBINACL, and ICACLS.  After hours studying and tinkering with these EXEs I was not able to find a satisfactory fit for our requirements.  Although they support SID translation and some form of an input file each tool was limited in some way or simply too out-dated to be of use.  Now please understand these are still amazing utilities, but for our specific scenario I could not get them to work.

Finally I considered the NAS vendor's ACL migration utility.  Most storage vendors have a suite of file migration utilities, including SID translation.  I found the tools in this case to be simplified and not scalable.  We need more POWER!

Enter PowerShell (aka Chuck Norris)

Our script today will help find and translate those old NTFS SIDs lingering behind on file server ACLs.

Basically the script traverses an NTFS path (local or UNC) and swaps any ACE SIDs that it finds in the SID mapping file.  At the end it outputs a text file verbose log and a CSV with all folders and any SID mappings identified.  Use the WhatIf switch to run in audit mode and check for SID history without making any changes.  In the interest of efficiency we only scan folder permissions; you can modify the script quickly to do both files and folders if desired.  We also ignore owner information in the ACL.

The Round House Kick

The Big O Notation to check every SID in every ACL against every row of the SID mapping file would be quite large.  (This is the problem with some of the EXEs we mentioned earlier.)  The beauty of PowerShell is that we can do the SID mapping quickly with a hash table, and that is the heart of the magic.

First, we read the mapping file into a hash table:

$SIDMapHash=@{}Import-CSV$MapFile|ForEach-Object{$SIDMapHash.Add($_.OldSID,$_.NewSID)}

The key If statement buried in the heart of our SID searching loop simply does a Contains method against the hash table:

If ($SIDMapHash.Contains($ACLEntrySID)) {#We have a winner}

This lightning-fast technique saves us from traversing the entire mapping file each time we search for a SID match.  Each time we find a match we do the old switcheroo with the old SID and new SID in the ACE.

$SDDLSplit[$i]=$SDDLSplit[$i].Replace($ACLEntrySID,$SIDMapHash.($ACLEntrySID))

When we finish swapping SIDs in the ACEs we write back the change with Set-ACL.

$acl.SetSecurityDescriptorSddlForm($NewSDDL)Set-Acl-Path$acl.path-ACLObject$acl

See the full code in the attached zip file, including sample output.  There is also a fancy progress bar as we scan the folders.  Think of the progress dots as Chuck Norris' foot flying to the target.  I finally followed The Scripting Guy's advice and took the time to add all the bells and whistles... comment-based help, advanced functions, parameter validation, etc.  With each new post I'll build this function library into a full dojo of karate moves.

Explicit Instructions

As always you should test scripts like this in a lab or on a small subset of data until you are comfortable with what it will do in production.  I have also provided a couple backup options in these steps:

  1. Make sure you have a full backup from the night before.
  2. Notify your backup administrator that you could potentially trigger a significant list of file backups if your software treats ACL changes as backup triggers.
  3. For the PowerShell console use Run As with sufficient credentials to edit security on all subfolders in the path specified.
  4. Use ICACLS to save a permissions template so that it can be reapplied in the event of an issue.
  5. Dot-source the script file (dot space dot backslash script file):
       PS C:\>. .\SIDHistory.ps1
  6. For instructions use Get-Help -Full to read about each function:
       PS C:\>Get-Help Export-SIDMapping -Full
       PS C:\>Get-Help Convert-SIDHistoryNTFS -Full
  7. Create a SID mapping file:
       PS C:\>Export-SIDMapping
  8. Review the report files, proceed with WhatIf first.
  9. PS C:\>Convert-SIDHistoryNTFS \\server\share\path -WhatIf
  10. Review the report files, decide to remove WhatIf and commit the changes.
  11. PS C:\>Convert-SIDHistoryNTFS \\server\share\path
  12. Review the report files.
  13. Have your users test file access and login script drive mappings to make sure everyone is still happy.

Coming Up Next

Today's function library is not a full replacement for SIDWALK or ADMT.  It just does NTFS permissions for wherever you point it.  Next time we'll look at how to get a list of Domain SIDs in your environment so that you can interpret where SID history is coming from.  Now go unleash your Norris moves on the NAS.

For More Information

 PS... I'm running out of Chuck Norris lines.  Add yours in the comments below, and I'll put them in the next post.

Active Directory OU Permissions Report: Free PowerShell Script Download

$
0
0

Who owns your OUs?MP900309543[1]

Have you ever lost your keys? It is a scary feeling. Someone out there could have keys to your house and your car. Your personal safety could be at risk. The same is true in Active Directory.  Do you know who has the keys to all of your accounts?

The Problem

In Active Directory we need to know who has the keys to our organizational units (OUs), the place where our users and computers live. Over the years OUs have grown to meet needs. Different teams may have been delegated access for managing users, groups, and computers. Then you come along as the new administrator. You probably have no idea where permissions have been granted to your OUs. And the scary thing is… neither does anyone else.  I know, because I’ve been there.  I hear the same thing from our customers.

Out-of-the-box we do not have a specific tool to report all of the OU permissions. You have to click each OU and view the security tab one-by-one, and we all know that is entirely impractical.  Today’s post contains a script download to generate a report of this vital information.

OU Permissions

OU permissions are multi-faceted. In other words… it’s complicated. They have a number of properties:

  • Principal
  • Allow/Deny
  • Scope
  • Applies To
  • Permissions

You’ll see the following dialog when you add a permission. This is enough to explain the complexity of the group access notation:

clip_image002

Now look how many Applies to: options there are.  Notice that this box scrolls a long way.

clip_image003

What we need is a report that lists the contents of the Advanced permissions GUI like this for every OU:

clip_image005

The matrix of potential permission configurations is mind-blogging.

The Solution: PowerShell

I had wondered if a report like this could be as simple as:

Import-Module ActiveDirectory
cd AD:
dir –recurse –directory | Get-ACL

Of course what works in our imaginations is rarely as simple in real life.  No, that code would not do it.  However, the concept is the same:

  • Get a list of all OUs
  • Loop through the OUs to retrieve their permissions
  • Export all data to a CSV file

Our good friend Get-ACL reports on more than file system permissions.  We can use this same cmdlet to query OU permissions as well.  Notice that we preface the OU distinguished name with AD:\.  Any time you query permissions with Get-ACL you need to expand the Access property to see the list of permission entries (ACEs):

Get-Acl -Path "AD:\OU=Domain Controllers,DC=wingtiptoys,DC=local" |
  Select-Object -ExpandProperty Access

Here is an example of an ActiveDirectoryAccessRule object that is returned for an OU:

image

We get an entry like this for every permission assigned to the OU.  My first instinct was to simply dump a list of these to CSV and be done with it.  But then I noticed the ObjectType and InheritedObjectType properties.  Hmmmm.  These are ugly GUIDs… not what we need for the report.  We need to translate these to the names of the objects that receive the permissions.  These names are what we see in that long drop-down list in the screenshot above.

To make a long story short I stayed up until 3AM researching this and traced it all down in the Active Directory Technical Specifications (MS-ADTS) here:

You are welcome to read these pages for yourself to understand the relationships.  Essentially these GUID values are stored on attributes of selected objects in the schema and configuration partitions of the AD database.  You can query these to build a list of names that will make the report readable.  So that’s what I did and put them into a hash table for quick look-ups when we generate the report.

The Big Finish

When we script it all out we get a report that looks something like this:

image

Obviously there are too many columns to read in the screenshot, but it is quite thorough.  Now you can use filters and pivot tables in Excel to analyze the data and produce reports showing exactly which OUs have delegated permissions, what kind of permissions, and who has them.  Likewise you can pivot the report by group to see a list of all OUs that a group can control.  You may want to filter the output by the IsInherited property.  By filtering for FALSE you will find everywhere that permissions are explicitly delegated in the OU tree.

Conclusion

I would advise all Active Directory shops to run and review this report on a quarterly basis to make sure there are no surprise administrators lurking in your domain. The report can be quite large for any size organization.  Perhaps this would be a good report to feed to the Information Security team, if you have one.  Now you know who holds the keys.

 

Download the full script from the TechNet Script Gallery.

PowerShell: SID Walker, Texas Ranger (Part 1)

$
0
0

SID Walker

First things first:

  1. If Chuck Norris wrote a PowerShell script it would be a one-liner, because Chuck Norris can do anything in one strike.
  2. Chuck Norris does not have SID history, because there is only one Chuck Norris.
  3. Chuck Norris' ACL only has one ACE: Chuck Norris – Full Control.

Do you remember SIDWALK?  This resource kit utility was written back in the NT 4.0 days to assist with domain migrations.  It used a mapping file to rewrite old SIDs with new SIDs across ACLs in a number of areas:  files shares, printer shares, registry paths, NTFS permissions, etc.  That utility is a teenager now (born 1998).  It's time we rewrite this and bring it up to date… in PowerShell.

Sidwalk V1.0
Copyright (C) 1998 Microsoft Corporation
Usage: Sidwalk <profile file> [<profile file> ..] [/t /f [<path>] /r /s /p /g /l <file>]

In part one of this series we will learn how to parse SIDs out of SDDL that we receive from Get-ACL.  This handy cmdlet works with many of these permissions.  Once we get the SIDs parsed out of SDDL, a future post will walk us through swapping them out and updating them.

Why SID Walker?  Why PowerShell?

One of my favorite Active Directory topics is SID history and its impact on token size.  In my former post I discussed creating a SID mapping file by querying SID history data from AD.  Eventually I plan to release a PowerShell module for remediating token size issues due to SID history.  This series on SID translation will be the centerpiece of that module.

Whether you are doing a domain migration, cleaning up SID history, or doing a search-and-replace for a group migration project this script will become your BFF.

Terms of Security

Most of us already know these terms, but let me define a few of these up front for anyone who is not familiar with them:

  • ACLAccess Control List– This is the list of permissions on a resource (file, folder, registry key, etc.).  ACLs contain ACEs.
  • ACEAccess Control Entry– This is an individual permission entry on an ACL.  An example would be TEXAS\cnorris Allow FullControl.
  • SDDLSecurity Descriptor Definition Language– This is a short-hand string that represents the entire ACL in a single, encoded string.  See MSDN for the specifics.
  • SIDSecurity Identifier– This is the unique security GUID that is assign to all security principles in a domain (users, computers, groups).  SIDs live in ACEs to represent the users who get the access.

Get-ACL

Editing ACLs with VBScript was a royal pain, but now we have the Get-ACL and Set-ACL cmdlets in PowerShell.  Setting and getting permissions on the file system, registry, and even AD organizational units has become a one-liner.  Look at the sample output for Get-ACL below:

PS C:\Users\ashley> Get-ACL | gm

TypeName: System.Security.AccessControl.DirectorySecurity

Name            MemberType      Definition
----            ----------      ----------
Access          CodeProperty    System.Security.AccessControl.Auth...
Sddl            CodeProperty    System.String Sddl{get=GetSddl;}
AccessToString  ScriptProperty  System.Object AccessToString {get=...

<<output trimmed>>

 

PS C:\Users\ashley> Get-ACL | fl *


PSPath                  : Microsoft.PowerShell.Core\FileSystem::C:\Users\ashley
PSParentPath            : Microsoft.PowerShell.Core\FileSystem::C:\Users
PSChildName             : ashley
PSDrive                 : C
PSProvider              : Microsoft.PowerShell.Core\FileSystem
AccessToString          : NT AUTHORITY\SYSTEM Allow  FullControl
                          BUILTIN\Administrators Allow  FullControl
                          NADOMAIN\ashley Allow  FullControl
AuditToString           :
Path                    : Microsoft.PowerShell.Core\FileSystem::C:\Users\ashley
Owner                   : NT AUTHORITY\SYSTEM
Group                   : NT AUTHORITY\SYSTEM
Access                  : {System.Security.AccessControl.FileSystemAccessRule, System.Security.AccessControl.FileSystemAccessRule, System.Security.AccessControl.FileSystemAccessRule}
Sddl                    : O:SYG:SYD:P(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;FA;;;S-1-5-21-468525095-708123637-3513119021-43309)
AccessRightType         : System.Security.AccessControl.FileSystemRights
AccessRuleType          : System.Security.AccessControl.FileSystemAccessRule
AuditRuleType           : System.Security.AccessControl.FileSystemAuditRule
AreAccessRulesProtected : True
AreAuditRulesProtected  : False
AreAccessRulesCanonical : True
AreAuditRulesCanonical  : True

 

PS C:\Users\ashley> (Get-ACL).Access | fl *

FileSystemRights  : FullControl
AccessControlType : Allow
IdentityReference : NT AUTHORITY\SYSTEM
IsInherited       : False
InheritanceFlags  : ContainerInherit, ObjectInherit
PropagationFlags  : None

FileSystemRights  : FullControl
AccessControlType : Allow
IdentityReference : BUILTIN\Administrators
IsInherited       : False
InheritanceFlags  : ContainerInherit, ObjectInherit
PropagationFlags  : None

FileSystemRights  : FullControl
AccessControlType : Allow
IdentityReference : NORTHAMERICA\asmcglon
IsInherited       : False
InheritanceFlags  : ContainerInherit, ObjectInherit
PropagationFlags  : None

Get-ACL gives us the same ACL in three different properties:

  1. AccessToString– This is a simplified representation to get a summary of the ACEs.
  2. Access– This is an array of access rule objects with rich properties.  Enumerating these is the easiest way to script and report against ACLs.
  3. SDDL– This is the only place where you can see the actual SIDs behind the ACEs.  For our purposes of SID translation we'll have to use this property.

You can pass any file, registry, or OU path to Get-ACL.  Without the path it defaults to the local context.  See "Get-Help Get-ACL -Full" for more information.

SDDL

Although it looks cryptic, a few minutes of study on MSDN will help you crack the code and break down what is happening in the SDDL string.  Notice the string in the example below (note that the SID has been changed to protect the innocent):

O:SYG:SYD:P(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;FA;;;S-1-5-21-468525095-708123637-3513119021-43309)

Look what happens when we break it down by the parentheses:

  1. O:SYG:SYD:P
  2. (A;OICI;FA;;;SY)
  3. (A;OICI;FA;;;BA)
  4. (A;OICI;FA;;;S-1-5-21-468525095-708123637-3513119021-43309)

The first piece contains owner and primary group information.  We're going to skip this for now; SIDs can live here, but we are targeting ACEs specifically.  The next three pieces delimited in parentheses correspond to each of the three ACEs in the ACL.  Note that the last one contains a SID, because it references a non-default account in the ACE.

Now let's break down that last ACE.  Observe that ACEs are delimited with semicolons:

  1. A;
  2. OICI;
  3. FA;
  4. ;
  5. ;
  6. S-1-5-21-468525095-708123637-3513119021-43309

The "A" means "allow".  "OI" and "CI" reference "ObjectInherit" and "ContainerInherit" as observed in the full output of the Access property listed above.  These denote that permissions set at this level will be inherited downward.  If this value contained "ID", then we would know that the values where inherited from above and not explicitly defined at this level.  You can read about the other specific SDDL coding on MSDN.

The last element of the ACE array contains the SID, and that is our target for this script.  The user or group SID will always live in the 5th array index of each ACE.  If there is no SID here, then you'll find an alpha code representing a well-known group.

Finding SIDs in ACLs

To summarize our breakdown of SDDL above you can find the ACL SIDs using the process below:

  1. Get the ACL
  2. Get the SDDL string of the ACL
  3. Split the SDDL on parentheses to get the ACEs
  4. Split the ACEs on semicolons
  5. Reference the last index of the ACE array to find the SID

While this may seem like a lot of effort that is exactly what PowerShell does best.  We'll wrap this process into a function to reuse and call for each ACL that we want to parse.

Why all of this trouble?  Why not use the robust Access property array?  Remember that we are translating SIDs, and this is the only place where we can find them.  Both the regular account SID and the SID history will appear the same in the DOMAIN\username representation of the Access property ACE objects.  This is an important distinction.

The Code

The script attached to this blog gives you a basic function to parse SDDL as described above.  As an educational script it includes much verbose output and comments.  Study the output to learn more about how ACLs, ACEs, and SDDL work in different security contexts (file system vs. registry vs. AD).  Customize it for your own needs.  Note that we ignore any ACEs that are inherited, because we only want to target ACEs with explicit permissions for translation.

Coming Up Next

The next post in this series will adapt this function into a larger script that mimics SIDWALK by translating SIDs on file resources.  We'll learn how to unleash your inner Chuck Norris round house kick on SID history.

<#---------------------------------------------------------------------------
 Ashley McGlone, Microsoft PFE
http://blogs.technet.com/b/ashleymcglone
 August, 2011
 Parse-SDDL function.
http://msdn.microsoft.com/en-us/library/aa374928.aspx
 ace_type;ace_flags;rights;object_guid;inherit_object_guid;account_sid
 0 ;1 ;2 ;3 ;4 ;5
 0 ;ID ;2 ;3 ;4 ;SID
 Split the SDDL on the characer: (
 Process indexes 1 to end
 Split on character ;
 If index 1 contains "ID" then ignore because inherited
 If index 5 contains a SID then process it
---------------------------------------------------------------------------#>functionParse-SDDL{[CmdletBinding()]param([Parameter(valueFromPipelineByPropertyName=$true)]$SDDL)$SDDLSplit=$SDDL.Split("(")"`n---SDDL Split:"$SDDLSplit"`n---SDDL SID Parsing:"# Skip index 0 where owner and/or primary group are storedFor($i=1;$i-lt$SDDLSplit.Length;$i++){$ACLSplit=$SDDLSplit[$i].Split(";")If($ACLSplit[1].Contains("ID")){"Inherited"}Else{$ACLEntrySID=$null# Remove the trailing ")"$ACLEntry=$ACLSplit[5].TrimEnd(")")# Parse out the SID using a handy RegEx$ACLEntrySIDMatches=[regex]::Matches($ACLEntry,"(S(-\d+){2,8})")$ACLEntrySIDMatches|ForEach-Object{$ACLEntrySID=$_.value}If($ACLEntrySID){$ACLEntrySID}Else{"Not inherited - No SID"}}}#return $null}# Experiment with these different path values to see what the ACL objects do$path="C:\users\username\"#Not inherited$path="C:\users\username\desktop\"#Inherited$path="HKCU:\"#Not Inherited$path="HKCU:\Software"#Inherited$path="HKLM:\"#Not Inherited"`n---Path:"$Path$ACL=Get-ACL$path"`n---Access To String:"$ACL.AccessToString"`n---Access entry details:"$ACL.Access|fl*"`n---SDDL:"$ACL.SDDL# Call with named parameter binding$ACL|Parse-SDDL# Call with parameter string#Parse-SDDL $ACL.SDDL# ><>

PowerShell: SID Walker, Texas Ranger (Part 2)

$
0
0

More bad Chuck Norris one liners:

  1. You don't get access unless Chuck Norris says you get access.
  2. The Chuck Norris array starts and ends on 1, because Chuck Norris is never a zero.
  3. Chuck Norris' PowerShell console NEVER shows red text.

This is part two in a series on translating SIDs in ACLs.  Start by reading Part One if you haven't done so already.  Today we're going to unleash a Chuck Norris round house kick on old SIDs stinking up our file servers.  It's time to take out the trash.

The Scenario

In my former post on SID history I explained…

Tell me if this scenario has ever happened at your company. You are doing an AD migration with the ADMT (or a similar product). You migrated the users and groups. The project schedule was falling behind. You take a shortcut with the member servers. Instead of using the ADMT security translation process you just rejoin the servers to the new domain, leaving all of the old ACLs and SIDs untouched. You leave SID history in place and move on to the next big project and deadline.

The Requirements

We need a solution that will

  • Scan a file server
  • Find all of the NTFS permissions (ACLs)
  • Find the SIDs in those permissions (ACEs)
  • Compare each ACE SID to our SID history mapping file to see if it needs swapped
  • Swap the old SID with the new SID

An Added Twist… The NAS

The ADMT (Active Directory Migration Tool) is the ideal solution, well almost.  An added complexity here is that many companies migrate Windows file servers to a NAS (network attached storage).  The ADMT does security translation by deploying an agent that runs on Windows servers and translates all of the SIDs locally.  Since a NAS is not a Windows server, the ADMT is powerless to translate the SIDs stored there.  The security translation agent cannot run on a NAS.  I know what you're thinking, though.  "From a Windows server just map the NAS as a drive or mount it under a local folder.  Then the ADMT will see it."  That's what I thought, too.  We're both wrong.  After rereading the ADMT guide, trying a few work-arounds, and confirming this internally I have realized that the ADMT simply cannot work with a NAS.  (If you've done it I would love to hear your story.)

Then I turned to a host of utilities that have been around for years:  SIDWALK, SHOWACCS, SUBINACL, and ICACLS.  After hours studying and tinkering with these EXEs I was not able to find a satisfactory fit for our requirements.  Although they support SID translation and some form of an input file each tool was limited in some way or simply too out-dated to be of use.  Now please understand these are still amazing utilities, but for our specific scenario I could not get them to work.

Finally I considered the NAS vendor's ACL migration utility.  Most storage vendors have a suite of file migration utilities, including SID translation.  I found the tools in this case to be simplified and not scalable.  We need more POWER!

Enter PowerShell (aka Chuck Norris)

Our script today will help find and translate those old NTFS SIDs lingering behind on file server ACLs.

Basically the script traverses an NTFS path (local or UNC) and swaps any ACE SIDs that it finds in the SID mapping file.  At the end it outputs a text file verbose log and a CSV with all folders and any SID mappings identified.  Use the WhatIf switch to run in audit mode and check for SID history without making any changes.  In the interest of efficiency we only scan folder permissions; you can modify the script quickly to do both files and folders if desired.  We also ignore owner information in the ACL.

The Round House Kick

The Big O Notation to check every SID in every ACL against every row of the SID mapping file would be quite large.  (This is the problem with some of the EXEs we mentioned earlier.)  The beauty of PowerShell is that we can do the SID mapping quickly with a hash table, and that is the heart of the magic.

First, we read the mapping file into a hash table:

$SIDMapHash=@{}Import-CSV$MapFile|ForEach-Object{$SIDMapHash.Add($_.OldSID,$_.NewSID)}

The key If statement buried in the heart of our SID searching loop simply does a Contains method against the hash table:

If ($SIDMapHash.Contains($ACLEntrySID)) {#We have a winner}

This lightning-fast technique saves us from traversing the entire mapping file each time we search for a SID match.  Each time we find a match we do the old switcheroo with the old SID and new SID in the ACE.

$SDDLSplit[$i]=$SDDLSplit[$i].Replace($ACLEntrySID,$SIDMapHash.($ACLEntrySID))

When we finish swapping SIDs in the ACEs we write back the change with Set-ACL.

$acl.SetSecurityDescriptorSddlForm($NewSDDL)Set-Acl-Path$acl.path-ACLObject$acl

See the full code in the attached zip file, including sample output.  There is also a fancy progress bar as we scan the folders.  Think of the progress dots as Chuck Norris' foot flying to the target.  I finally followed The Scripting Guy's advice and took the time to add all the bells and whistles... comment-based help, advanced functions, parameter validation, etc.  With each new post I'll build this function library into a full dojo of karate moves.

Explicit Instructions

As always you should test scripts like this in a lab or on a small subset of data until you are comfortable with what it will do in production.  I have also provided a couple backup options in these steps:

  1. Make sure you have a full backup from the night before.
  2. Notify your backup administrator that you could potentially trigger a significant list of file backups if your software treats ACL changes as backup triggers.
  3. For the PowerShell console use Run As with sufficient credentials to edit security on all subfolders in the path specified.
  4. Use ICACLS to save a permissions template so that it can be reapplied in the event of an issue.
  5. Dot-source the script file (dot space dot backslash script file):
       PS C:\>. .\SIDHistory.ps1
  6. For instructions use Get-Help -Full to read about each function:
       PS C:\>Get-Help Export-SIDMapping -Full
       PS C:\>Get-Help Convert-SIDHistoryNTFS -Full
  7. Create a SID mapping file:
       PS C:\>Export-SIDMapping
  8. Review the report files, proceed with WhatIf first.
  9. PS C:\>Convert-SIDHistoryNTFS \\server\share\path -WhatIf
  10. Review the report files, decide to remove WhatIf and commit the changes.
  11. PS C:\>Convert-SIDHistoryNTFS \\server\share\path
  12. Review the report files.
  13. Have your users test file access and login script drive mappings to make sure everyone is still happy.

Coming Up Next

Today's function library is not a full replacement for SIDWALK or ADMT.  It just does NTFS permissions for wherever you point it.  Next time we'll look at how to get a list of Domain SIDs in your environment so that you can interpret where SID history is coming from.  Now go unleash your Norris moves on the NAS.

For More Information

 PS... I'm running out of Chuck Norris lines.  Add yours in the comments below, and I'll put them in the next post.

Active Directory OU Permissions Report: Free PowerShell Script Download

$
0
0

Who owns your OUs?

Have you ever lost your keys? It is a scary feeling. Someone out there could have keys to your house and your car. Your personal safety could be at risk. The same is true in Active Directory.  Do you know who has the keys to all of your accounts?

The Problem

In Active Directory we need to know who has the keys to our organizational units (OUs), the place where our users and computers live. Over the years OUs have grown to meet needs. Different teams may have been delegated access for managing users, groups, and computers. Then you come along as the new administrator. You probably have no idea where permissions have been granted to your OUs. And the scary thing is… neither does anyone else.  I know, because I’ve been there.  I hear the same thing from our customers.

Out-of-the-box we do not have a specific tool to report all of the OU permissions. You have to click each OU and view the security tab one-by-one, and we all know that is entirely impractical.  Today’s post contains a script download to generate a report of this vital information.

OU Permissions

OU permissions are multi-faceted. In other words… it’s complicated. They have a number of properties:

  • Principal
  • Allow/Deny
  • Scope
  • Applies To
  • Permissions

You’ll see the following dialog when you add a permission. This is enough to explain the complexity of the group access notation:

clip_image002

Now look how many Applies to: options there are.  Notice that this box scrolls a long way.

clip_image003

What we need is a report that lists the contents of the Advanced permissions GUI like this for every OU:

clip_image005

The matrix of potential permission configurations is mind-blogging.

The Solution: PowerShell

I had wondered if a report like this could be as simple as:

Import-Module ActiveDirectory
cd AD:
dir –recurse –directory | Get-ACL

Of course what works in our imaginations is rarely as simple in real life.  No, that code would not do it.  However, the concept is the same:

  • Get a list of all OUs
  • Loop through the OUs to retrieve their permissions
  • Export all data to a CSV file

Our good friend Get-ACL reports on more than file system permissions.  We can use this same cmdlet to query OU permissions as well.  Notice that we preface the OU distinguished name with AD:\.  Any time you query permissions with Get-ACL you need to expand the Access property to see the list of permission entries (ACEs):

Get-Acl -Path "AD:\OU=Domain Controllers,DC=wingtiptoys,DC=local" |
  Select-Object -ExpandProperty Access

Here is an example of an ActiveDirectoryAccessRule object that is returned for an OU:

image

We get an entry like this for every permission assigned to the OU.  My first instinct was to simply dump a list of these to CSV and be done with it.  But then I noticed the ObjectType and InheritedObjectType properties.  Hmmmm.  These are ugly GUIDs… not what we need for the report.  We need to translate these to the names of the objects that receive the permissions.  These names are what we see in that long drop-down list in the screenshot above.

To make a long story short I stayed up until 3AM researching this and traced it all down in the Active Directory Technical Specifications (MS-ADTS) here:

You are welcome to read these pages for yourself to understand the relationships.  Essentially these GUID values are stored on attributes of selected objects in the schema and configuration partitions of the AD database.  You can query these to build a list of names that will make the report readable.  So that’s what I did and put them into a hash table for quick look-ups when we generate the report.

The Big Finish

When we script it all out we get a report that looks something like this:

image

Obviously there are too many columns to read in the screenshot, but it is quite thorough.  Now you can use filters and pivot tables in Excel to analyze the data and produce reports showing exactly which OUs have delegated permissions, what kind of permissions, and who has them.  Likewise you can pivot the report by group to see a list of all OUs that a group can control.  You may want to filter the output by the IsInherited property.  By filtering for FALSE you will find everywhere that permissions are explicitly delegated in the OU tree.

Conclusion

I would advise all Active Directory shops to run and review this report on a quarterly basis to make sure there are no surprise administrators lurking in your domain. The report can be quite large for any size organization.  Perhaps this would be a good report to feed to the Information Security team, if you have one.  Now you know who holds the keys.

 

Download the full script from the TechNet Script Gallery.

PowerShell to Find Where Your Active Directory Groups Are Used On File Shares

$
0
0

Happy St. Patrick’s Day!  Enjoy some PowerShell limericks hereDownload today’s script from the TechNet Script Gallery.

Where are my AD groups used?

Today's post gives you a script to crawl your file shares and document the AD users and groups referenced in NTFS permissions.  I’m sure others have published similar scripts, but I want to approach it from the angle of Active Directory group cleanup. Using this output together with the script from my last post will give you plenty of insight to go after stale groups.

Leprechaun

Finish this familiar quote, “I can’t delete that group, because ______________ .”  Multiple choice:

  • “I have no idea where it is used.”
  • “The last admin told me to never delete that group.”
  • “That is how the leprechauns get access.”
  • All of the above.

What would we do without file shares?  Well, actually, we would use SharePoint or OneDrive. The truth is file shares have been around for decades, and in most cases mission critical data resides there.  But who can access that data?  That is the big question, and many of us cannot give a complete answer.

By the way, if you would like a security report for SharePoint group usage, my peer, Brian Jackett, has a script for that.  (That sentence had more commas than a CSV file.)

The Solution

Our solution today involves two scripts:

  • Get Access Control Entries.  This script scans file server paths provided by an input text file.  The text file simply lists the root UNC path to every share you want to scan. It exports a CSV report of all explicitly defined (not inherited) permissions at the folder level recursively down a file share path.
  • Merge CSV NTFS Scans.  This script combines all of the individual CSV permission reports into a single file for importing into a database.

In my SID history series I included a function to scan file shares for SID history and migrate the NTFS ACL entries to the new SID.  Basically I retooled that code to simply report all access and ignore SID history. This time, however, I used the Access property instead of the SDDL property.  I recommend that you read this particular post for more background information.

The Code

This script is really not that complicated, so it will be a good one to study if you’re learning PowerShell.  The main cmdlet is Get-ACL.  Everything else is loops, error checking, and progress bars.

First, populate paths.txt with local drive paths and/or UNC paths for the root of each share to scan. For each path in the file you will get two CSV output files:

  • ACEs– An exhaustive list of every user or group explicitly assigned permissions at the folder level all the way down the tree.
  • Errors– Here you will find the folder paths with error messages encountered during the scan.  Popular errors include Access Denied and Path Too Long.

Be sure to review the error log for each share scanned.  You may need to run another scan with different credentials.

#Requires -Version 3.0FunctionGet-ACE{Param([parameter(Mandatory=$true)][string][ValidateScript({Test-Path-Path$_})]$Path)$ErrorLog=@()Write-Progress-Activity"Collecting folders"-Status$Path`-PercentComplete0$folders=@()$folders+=Get-Item$Path|Select-Object-ExpandPropertyFullName$subfolders=Get-Childitem$Path-Recurse-ErrorVariable+ErrorLog`-ErrorActionSilentlyContinue|Where-Object{$_.PSIsContainer-eq$true}|Select-Object-ExpandPropertyFullNameWrite-Progress-Activity"Collecting folders"-Status$Path`-PercentComplete100# We don't want to add a null object to the list if there are no subfoldersIf($subfolders){$folders+=$subfolders}$i=0$FolderCount=$folders.countForEach($folderin$folders){Write-Progress-Activity"Scanning folders"-CurrentOperation$folder`-Status$Path-PercentComplete($i/$FolderCount*100)$i++# Get-ACL cannot report some errors out to the ErrorVariable.# Therefore we have to capture this error using other means.Try{$acl=Get-ACL-LiteralPath$folder-ErrorActionContinue}Catch{$ErrorLog+=New-ObjectPSObject`-Property@{CategoryInfo=$_.CategoryInfo;TargetObject=$folder}}$acl.access|Where-Object{$_.IsInherited-eq$false}|Select-Object`@{name='Root';expression={$path}},`@{name='Path';expression={$folder}},`IdentityReference,FileSystemRights,IsInherited,`InheritanceFlags,PropagationFlags}$ErrorLog|Select-ObjectCategoryInfo,TargetObject|Export-Csv".\Errors_$($Path.Replace('\','_').Replace(':','_')).csv"`-NoTypeInformation}# Call the function for each path in the text fileGet-Content.\paths.txt|ForEach-Object{If(Test-Path-Path$_){Get-ACE-Path$_|Export-CSV`-Path".\ACEs_$($_.Replace('\','_').Replace(':','_')).csv"`-NoTypeInformation}Else{Write-Warning"Invalid path: $_"}}

 

Disclaimers

  • This will likely take hours or days to run depending on the size of your shares.
  • You must run this script from PowerShell v3 or later.
  • Paths longer than 260 characters will error.
  • You must run the script with permissions to read all of the folders down the file share tree.
  • In order to keep the script as efficient as possible we do not scan individual file permissions.
  • This script does not look at the share permissions, only NTFS. In my field experience most places use Everyone/FullControl on their share roots and manage permissions with NTFS.

 

Roll ‘em Up

I included a bonus script that will merge all of the CSV output. This is rather short and sweet. It just saves you the time of doing it yourself. The result is a file called NTFSScan.CSV containing all of the CSV output rolled into one file.

The Next Level

Now that you have this rich group data in CSV format you can pull it all into a database for analysis. In the past I have used Microsoft Access for a quick proof-of-concept.  I pulled in the group report, group duplication report, and the merged NTFS permission CSV output. (You could even pull in the AD organizational unit permission report.) I imported these from CSV to new Access tables.  Then I created some queries that relate the data and report on things like:

  • Perfect match group memberships at 100%
  • Group counts by category and scope
  • Empty groups not updated in 12 months
  • Groups not used in NTFS permissions
  • Pivot table (cross tab) report of groups used on each server
  • Summary of groups used in NTFS permissions
  • Etc.

These reports will give you insight into the use of groups in your environment. You can also see where users are assigned permissions directly instead of using groups.

Group Cleanup

There are many factors that go into group cleanup.  Just because a group has not been updated in over one year does not always mean it is stale, especially for some of the built-in AD groups. Groups are used in so many places across the enterprise that it is nearly impossible to say that one is not in use at all. However, when combined with usage data like we collected with today’s script, we can get a far more accurate list of which groups are potentially stale. Go here for a list of other group cleanup posts.

Pro Tip: Instead of deleting a global group right away try this: change the group type to Distribution group. That will effectively remove it as a security group. That may be enough of a fail safe that you can flip it back to Global group should the need arise. If no one calls in the next 30 days, then there is a possibility you could completely delete it.

Pro Tip: When it comes time to clean up your groups make sure you have the AD Recycle Bin turned on and a full backup of your Active Directory.

With proper caution and investigation you should now have a good start on stale group cleanup. Happy hunting!

Download the full script from the TechNet Script Gallery.

PowerShell Video Training from Microsoft

$
0
0

People frequently ask me, “Where can I learn more about PowerShell?” Today’s post will highlight popular video training options available directly from Microsoft.

Microsoft Virtual Academy (MVA)Jeffrey and Jason having fun with DSC on MVA

There are many free, publicly available PowerShell video courses on Microsoft Virtual Academy. These cover a range of topics from core PowerShell features to Desired State Configuration (DSC), Active Directory, Exchange, SharePoint, Office 365 and more. Here are the most popular titles:

MSDN Channel9

Another avenue for free online PowerShell training is Channel9. Here you will find PowerShell video training from a number of sources and in a variety of languages in addition to English. This is a great place to find recorded sessions from TechEd and Ignite events.

edX

For a while Microsoft offered a paid PowerShell class on edX. That course has been archived now, but you can look there for popular Microsoft technology courses. Many of these are free.

Microsoft Premier Workshop Library on DemandDesired State Configuration With PowerShell v5.0 Video Series

You have many choices for training these days, both online and in the classroom. Microsoft Virtual Academy titles usually move fast to cover a lot of content. These Premier titles will dive deeper and slow down the pace to help with learning. Customers prefer training from Microsoft PFEs, because they get knowledge that comes from real-world experience of engineers working with customers of all sizes.

Microsoft Premier customers can get full-length, quality PowerShell training directly from Microsoft via streaming video at your convenience.The video training is an add-on item for Premier contracts. Not all Premier customers may have purchased this option, but they can always add it.

As a Microsoft Premier Field Engineer I teach many PowerShell workshops. Traditionally this has been classroom work, but over the last few years we have expanded our online offerings. We teach live remote workshops over Skype and use cloud-hosted labs. We also record training videos for you to stream on your schedule.

We call the online training videos Education as a Service and have given it the brand name Premier Workshop Library on Demand (WLOD).  Check out a YouTube video explaining it here.

What is available?

Find below the current list of PowerShell video workshops available for Premier customers through WLOD. The links below go directly to the courses once you are logged into the Premier Services portal.

  • Windows PowerShell v4.0 for the IT Professional, Part 1 – 14.5 hours – https://aka.ms/wpsp1
    Beginners start here. My buddy Gary and I will teach you all the essentials to start your journey as a PowerShell scripter. This is our most popular course of all Premier workshops!
  • Windows PowerShell v4.0 for the IT Professional, Part 2 – 12.5 hours – https://aka.ms/wpsp2
    Gary and I continue with deeper content on advanced functions, regular expressions, debugging, error handling, etc.
  • WorkshopPLUS – Windows PowerShell v5 Features – 11 hours – https://aka.ms/wpsv5
    This course covers the new PowerShell features released since the recording of the Part 1 and Part 2 workshops. Find detailed training on the new features in PowerShell WMF 5.0.
  • Desired State Configuration with PowerShell 5.0 – 17 hours – https://aka.ms/wpsdsc
    Everyone is talking about it. Learn it here. Ben and I spent time with customers in the field doing DSC, and then we wrote this course for you to learn it.

Here I have only listed the PowerShell titles. Essentially all of our Premier workshop titles are available on video now, so PowerShell is only the tip of the iceberg.

We’ve received a great deal of positive feedback from customers who love this stuff.

How do I get it?

Microsoft Premier customers with the WLOD subscription can access this offering; talk to your Premier Technical Account Manager (TAM) for more information and pricing.  If you would like to become a Premier customer go here.

To access the video courses follow these steps:

  • Go to https://services.premier.microsoft.com
  • Click Sign In
  • Log in with your Microsoft Account (Windows Live ID) that has been granted access to Workshop Library On-Demand. For questions contact your Premier TAM.
  • Click on My Education
  • Use the Category filter on the left to find Windows Server titles
  • Scroll through the list or use CTRL+F in the browser to find the specific PowerShell titles

You will have access to watch hundreds of Microsoft Premier workshop titles.

Microsoft Premier Webcast: PowerShell Ramp-Up Series

The Premier Webcast – PowerShell Ramp-Up Series is a collection of webcasts created with the goal of teaching from basic to more advanced PowerShell skills. No prior knowledge is necessary.

Beginning April 1, 2016 we have a special three month window of on-demand PowerShell training webcasts. Topics include:

  • Fundamentals to Advanced
  • Desired State Configuration
  • Advanced Functions
  • Workflow
  • Modules
  • Office 365
  • SQL
  • System Center
  • SharePoint
  • Security
  • And more…

This PowerShell Ramp-up Series offering allows developers and administrators to logon and view 16+ webcasts with a duration of approximately 2-hours each, which totals approximately 36 hours of PowerShell training. The content can be accessed anytime throughout the 3-month availability. Access starts on the first day of the first month and expires on the last day of the third month.

Sessions are delivered via on-demand streaming. In the recorded webcast, the instructor provides a combination of PowerPoint and demos in a rich and effective learning experience. Delivery time for each webcast is 90-120 minutes and the series contains a minimum of 16+ webcasts.

Contact your Microsoft Services Representative or TAM for more information and pricing.

What about non-Microsoft video training?

YouTube

Of course YouTube is packed with other video options as well. I especially want to point out that you can find most of the PowerShell Summit presentations there. MVPs, Microsoft PowerShell team members, and other members of the community present fantastic topics that are usually 300-400 level at this annual event previously held in North America and Europe. You will see expert demos in these videos that you will find nowhere else.

Others

There are many other video training options from MVPs and partners, ranging from free to paid. As a Microsoft employee I cannot endorse any one particular offering. However, I can tell you that many of the PowerShell MVPs record training for PluralSight. I have not watched any of that content, but I know many of these folks and trust them to do a great job.

Bonus Content: PowerScripting Podcast

One of my favorite resources for learning PowerShell prior to all of the video training options we have today has been the PowerScripting Podcast. This resource was created by two MVPs out of Atlanta, Jon and Hal. You can listen to interviews with many celebrities and MVPs in the world of PowerShell. They even have a chat room you can attend during the live podcast recordings to ask questions of the guests. I highly recommend this resource to customers as I deliver PowerShell training.

Get started today!

Surviving and thriving in the IT industry requires constant learning. PowerShell is a core skillset. Regardless of your current knowledge level of PowerShell, these resources will raise your game. Learn something new today!


Quick and easy Active Directory test lab using PowerShell DSC and AzureRM

$
0
0

That Active Directory Test Lab You Have Always Wanted

As a Microsoft Premier Field Engineer I have visited countless customers to assess and assist their Active Directory environment. Sadly, the majority of those customers do not have an Active Directory test environment. Today I am going to show you how to quickly deploy and destroy your own Active Directory test lab using Azure Resource Manager and PowerShell.

Build 10 new AD labs a day if you want. It is crazy easy and crazy fast using this script. Imagine going to your morning status meeting, and then coming back to an Active Directory domain ready for you to do your worst. When you are done, a single line of PowerShell erases the entire environment.

PowerShell and DevOps Global Summit 2016

Watch the demo and explanation of this code from the 2016 PowerShell Summit.

Quickly? Azure? In the same sentence?

Wait! Keep reading! I promise this is painless. I have done all the heavy lifting for you. All you need is an Azure subscription.

This solution is a mash up of the following technologies:

  • Azure
  • Azure DSC extension
  • PowerShell DSC
  • Azure Resource Manager (ARM) templates

Gone are the days of stumbling through the Azure interface to provision network, storage, compute, and sanity. Now using ARM templates you can spin up a complete environment with a couple lines of PowerShell. Yes, it can be that easy.

What’s in the secret sauce?

I started out by snagging a copy of a free AzureRM template for a domain controller. There is a large repository of sample templates on GitHub. Check it out.

I wanted to build my own DSC configuration for the domain, so I started with the included DSC configuration and added my own twist using a newer version of the xActiveDirectory DSC resource module (available on PowerShell Gallery and GitHub).

I watched Trevor Sullivan’s presentation on deploying AzureRM templates with PowerShell.

I asked my PFE buddy Ben Wilkinson for a head start with the calling code. He showed me how to get the Azure cmdlets installed and launch the template build.

I read a bunch of blog posts and documentation. You know how it is learning something new. You bang your head against the docs and your keyboard until you get a breakthrough. Here are some links that helped me:

https://azure.microsoft.com/en-us/blog/azps-1-0/
https://blogs.msdn.microsoft.com/powershell/2016/02/26/arm-dsc-extension-settings/
https://blogs.msdn.microsoft.com/powershell/2014/08/07/introducing-the-azure-powershell-dsc-desired-state-configuration-extension/
https://azure.microsoft.com/en-us/documentation/articles/automation-dsc-onboarding/
http://blogs.msdn.com/b/golive/archive/2015/09/01/developing-dsc-scripts-for-the-azure-resource-manager-dsc-extension.aspx
https://blogs.msdn.microsoft.com/powershell/2014/11/20/release-history-for-the-azure-dsc-extension/
https://blogs.msdn.microsoft.com/powershell/2015/06/17/azure-dsc-extension-v2-0-released/
https://blogs.msdn.microsoft.com/powershell/2014/09/10/secure-credentials-in-the-azure-powershell-desired-state-configuration-dsc-extension/

Then I hacked at it for a day until it worked.  :–)>  Now you get the benefit of a fully-functional solution.

After you install the Azure cmdlets you have just three commands to deploy your lab, and then one to blow it away when you are done:

  • Login-AzureRmAccount
  • New-AzureRmResourceGroup
  • New-AzureRmResourceGroupDeployment
  • Remove-AzureRmResourceGroup

Anyone working with AzureRM templates will probably tell you to use Visual Studio to create and edit them. And that is probably the easier way. However, I know many of you as infrastructure ops are not comfortable with Visual Studio dev tools. I wanted to prove that it can be done without the overhead of a massive Visual Studio install and license. I did some of my editing in the free, light-weight editor Visual Studio Code, but you could just as easily use Notepad or the PowerShell ISE to edit the json file.

How do I make my AD lab?

Usually my blog posts go into great detail and documentation for each script that I publish. In this case you can watch the video above for all the details. You will need WMF 5.0 installed before you get started.

I put the whole thing on GitHub for you to learn from. All you have to do is download CallingScript.ps1, edit the naming strings for uniqueness, and then run it a few lines at a time. The comments in the script will guide you. In 30 minutes you will have a populated AD test lab in Azure that you can connect to with RDP (remote desktop protocol). You could even copy and paste more scripts into the VM for further configuration or testing. Below is a screenshot of the finished domain controller.

RDP screenshot from the mobile client just for fun.

When you have more time, download all the files from my GitHub and dive into the DSC configuration and azuredeploy.json parts. Using the techniques I demonstrate in this code, you can tweak the domain sample data however you like. Then you can host your own version of these files on GitHub or Azure storage. You could even take just the DSC piece to build your own test lab in a local VM.

One parting piece of advice…

If you do not destroy the Azure resource group at the end of the day, then be sure to shutdown and deprovision the VMs in Azure. You pay for them as long as they are running. You can do this via the Azure portal or script. Consider yourself warned. Enjoy!

Who’s afraid of PowerShell security?

$
0
0

imageIs PowerShell a vulnerability?

Does your organization forbid the use of PowerShell remoting? Has InfoSec blocked remote server administration with PowerShell? Do you want to understand PowerShell security better? This post is for you.

Notes from the field…

As a Premier Field Engineer I have delivered PowerShell engagements to countless companies and teams. Over the years I have consistently received questions around PowerShell remoting security. More recently I have worked with multiple customers who had been tasked with restricting PowerShell capabilities in their environment. The conversation usually starts with one of these lines:

  • “InfoSec will not let us turn on PowerShell remoting.”
  • “Our last audit said that PowerShell needs to be locked down on all servers.”
  • “The CIO went to a security conference and then banned PowerShell from the environment.”

Now, be aware that these same companies will leave any one or more of these remote management ports open:

  • Remote Desktop Protocol (RDP)
  • Remote WMI access over RPC, clear text by default, random ports
  • Remote event log management
  • Remote service management
  • SMB file share access
  • PSEXEC

But they are afraid of:

  • PowerShell remoting, always encrypted, single port 5985 or 5986, does all of the above

Here are the key points for a PowerShell security conversation:

  • PowerShell is a neutral administration tool, not a vulnerability.
  • PowerShell remoting respects all Windows authentication and authorization protocols. It requires local Administrators group membership by default.
  • Hackers use PowerShell for the same reasons you do… because it is more convenient than twenty years of other popular command line tools.

Bottom Line

The improvements in WMF 5.0 (or WMF 4.0 with KB3000850) make PowerShell the worst tool of choice for a hacker when you enable script block logging and system-wide transcription. Hackers will leave fingerprints everywhere, unlike popular CMD utilities. For this reason, PowerShell should be the only tool you allow for remote administration. These features allow you to answer the classic questions who, what, when, where, and how for activities on your servers.

The links below provide documentation and training from Microsoft and other industry sources around securing PowerShell in the enterprise and enabling these key points above. Focus especially on the highlighted ones and anything from Lee Holmes.

Microsoft Resources

Download PowerShell WMF 5.0

Leverage all of the new security features in WMF 5.0.

http://microsoft.com/powershell

PowerShell Remoting Security Considerations

New security documentation from the PowerShell team. This is a start, and it will continue to be updated. Give this link to your InfoSec people who need more information.

https://msdn.microsoft.com/en-us/powershell/scripting/setup/winrmsecurity

PowerShell ♥ the Blue Team

Whitepaper by Lee Holmes “Scripting Security and Protection Advances in Windows 10” (PowerShell 5).

Give this to your InfoSec people, your manager, and your grandmother. Then implement it.

https://blogs.msdn.microsoft.com/powershell/2015/06/09/powershell-the-blue-team/

Just Enough Administration

JEA is how you restrict capabilities of remote PowerShell sessions. This is huge for securing your environment and a major thrust in Windows Server 2016 (available down level with WMF 5.0).

https://msdn.microsoft.com/powershell/jea/readme

Introducing the updated JEA Helper Tool

https://blogs.technet.microsoft.com/privatecloud/2015/12/20/introducing-the-updated-jea-helper-tool/

Windows Event Forwarding guidance

http://aka.ms/wef

Maslow’s Hierarchy of Security Controls

http://www.leeholmes.com/blog/2014/12/08/maslows-hierarchy-of-security-controls/

Use Windows Event Forwarding to help with intrusion detection

An operational guide for implementing WEF based on the experience of Microsoft IT in a large-scale environment

https://technet.microsoft.com/itpro/windows/keep-secure/use-windows-event-forwarding-to-assist-in-instrusion-detection

The Underhanded PowerShell Contest

Microsoft’s community effort to identify and defend against malicious PowerShell code.

https://github.com/PowerShell/underhanded-powershell

https://blogs.msdn.microsoft.com/powershell/2016/03/07/announcing-the-underhanded-powershell-contest/

Follow Lee Holmes on Twitter

PowerShell team security lead, Microsoft Lead Security Architect for Enterprise Cloud Group & Azure Stack. Constant stream of relevant info and links.

https://twitter.com/Lee_Holmes

PowerShell Remoting Exposed

An article that includes network traces comparing WMI, RPC, and WINRM/WSMAN PowerShell remoting protocols on the wire. It also includes a list of PowerShell help topics for more information.

https://blogs.technet.microsoft.com/ashleymcglone/2011/04/18/powershell-remoting-exposed-how-to-command-your-minions/

External Resources

NSA: Spotting the Adversary with Windows Event Log Monitoring

https://www.nsa.gov/ia/_files/app/spotting_the_adversary_with_windows_event_log_monitoring.pdf

Securing PowerShell in the Enterprise

Information security advice for all levels of government

Australian Signals Directorate, Australian Government Department of Defence

http://www.asd.gov.au/publications/protect/securing-powershell.htm

FireEye: Investigating PowerShell Attacks (BlackHat USA 2014)

https://www.fireeye.com/content/dam/fireeye-www/global/en/solutions/pdfs/wp-lazanciyan-investigating-powershell-attacks.pdf

Verizon 2016 Data Breach Investigations Report

Not PowerShell-specific, but good insight to breach techniques.

http://www.verizonenterprise.com/verizon-insights-lab/dbir/2016/

http://www.verizonenterprise.com/resources/reports/rp_DBIR_2016_Report_en_xg.pdf

Audio/Video

Microsoft Virtual Academy: What’s New in PowerShell v5

Lee Holmes and Ryan Puffer demonstrate security and JEA in WMF 5

http://aka.ms/MVAps5

PowerShell Security at DerbyCon 2016
Great list of security conference session recordings on the current landscape of PowerShell security. Includes talks by Jeffrey Snover and Lee Holmes.
https://blogs.msdn.microsoft.com/powershell/2016/09/27/powershell-security-at-derbycon

Security Weekly 460: Interview with Lee Holmes

https://www.youtube.com/watch?v=tzcabAVuJFw

RunAs Radio Podcast #471: Just Enough Admin and Windows Server 2016 with Jeffrey Snover

http://www.runasradio.com/default.aspx?ShowNum=471&utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+RunasRadio+%28RunAs+Radio+%28mp3%29%29

Microsoft Ignite 2015: JEA: A PowerShell Toolkit to Secure a Post-Snowden World

WMF 4.0 version of JEA

https://channel9.msdn.com/events/Ignite/2015/BRK2470

PowerShell Summit 2015: Managing PowerShell in the Enterprise Using Group Policy

Overview of GPOs involved for securing PowerShell

https://www.youtube.com/watch?v=NRnGP1RRNsM&index=20&list=PLfeA8kIs7CochwcgX9zOWxh4IL3GoG05P

PowerShell Summit 2015: Defending the Defenders Pt 1

Lee Holmes and MVP Jeff Hicks

https://www.youtube.com/watch?v=2HBTj0WU5lY&list=PLfeA8kIs7CochwcgX9zOWxh4IL3GoG05P&index=16

PowerShell Summit 2015: Defending the Defenders Pt 2

Lee Holmes and MVP Jeff Hicks

https://www.youtube.com/watch?v=mua7DhxamHs&list=PLfeA8kIs7CochwcgX9zOWxh4IL3GoG05P&index=17

PowerShell Summit 2015: Keeping Secrets

MVP Dave Wyatt

https://www.youtube.com/watch?v=Ta2hQHVKauo&index=19&list=PLfeA8kIs7CochwcgX9zOWxh4IL3GoG05P

PowerShell DSC 101: Using the Script Resource to Enable the Windows Firewall

$
0
0

imageLearning PowerShell Desired State Configuration

PowerShell DSC is one of my favorite topics to teach, because the technology is simply amazing. Usually I do not have enough time with a customer to teach all of the built-in resources. I would guess that the Script resource is one of the least understood. Today’s post outlines a simple example to enable the Windows Firewall. This sample will work on Windows Server 2008 R2 and above.

Automating Your Server Build Sheet

Last week I was on site with a customer doing a PS DSC POC (PowerShell Desired State Configuration Proof of Concept). We took their server build check sheet, identified DSC resources for each step, and then began converting their manual server config process into PowerShell DSC.

The customer was new to DSC and requested a sample of how they could use the built-in Script resource. One of the items on the build sheet was to make sure the Windows Firewall was turned on. This was the perfect opportunity for a Script resource example.

The Script Resource

When you cannot find a built-in DSC resource or community resource to do what you need you have two options for custom resource code:

  1. Built-In Script Resource – if the code is relatively simple, maybe just a couple lines
  2. Custom Resource – if the code requires complexities like helper functions, extensive variable use, etc.

The primary decision factor between these two is the level of effort and complexity required. If you can do it in a couple lines of code, then try using a Script resource first. If the code is more involved, then write a custom resource. Obviously a script resource is much less effort if you can get by with it.

In the case of the firewall example, there is a community resource xDSCFirewall that might suffice, but it does not work on Windows Server 2008 R2.

Script Resource Firewall Example

Here is an elegantly simple use of the Script resource. We could make it more complex in many ways, but I prefer to start out with a simple use case first. The code is its own documentation. Study it carefully.

Configuration FirewallScriptResource
{
    Import-DscResource -ModuleName PSDesiredStateConfiguration
    Node localhost
    {
        Script EnableFirewall
        {
            # Must return a hashtable with at least one key
            # named 'Result' of type String
            GetScript = {
                Return @{
                    Result = [string]$(netsh advfirewall show allprofiles)
                }
            }

            # Must return a boolean: $true or $false
            TestScript = {
                If ((netsh advfirewall show allprofiles) -like "State*off*") {
                    Write-Verbose "One or more firewall profiles are off"
                    Return $false
                } Else {
                    Write-Verbose "All firewall profiles are on"
                    Return $true
                }
            }

            # Returns nothing
            SetScript = {
                Write-Verbose "Setting all firewall profiles to on"
                netsh advfirewall set allprofiles state on
            }
        }
    }
}

FirewallScriptResource

Start-DscConfiguration -Path .\FirewallScriptResource -Wait -Verbose

Get-DscConfiguration

Notice the Write-Verbose statements. These are important for logging and output when the resource runs.

Notice that the GetScript, TestScript, and SetScript do not use a variable (except $true and $false). You could use custom variables in this code, for example, to reference parameters. See Example 2 of the Script resource documentation for how to use the $using: prefix with variables in a Script resource.

Take it to the next level.

There are many directions you could take this example:

  • Add a parameter for Enable vs. Disable.
  • Add a parameter for a specific firewall profile.
  • Filter the output of NETSH to only show the profile status portion (netsh advfirewall show allprofiles | Where-Object {$_ -like ‘*Profile*’ -or $_ -like ‘State*’})
  • Put the script resource into a composite resource to hide the Get/Test/Set code and keep your config looking clean.

Your Turn

Now it is your turn. Take this sample and implement your own script resources. Leave a comment below telling what you accomplished.

Best wishes on your adventure learning DSC!

PowerShell Remoting Kerberos Double Hop Solved Securely

$
0
0

The struggle is real.

Are you facing issues with PowerShell remoting and credentials? You remote into your jump box, but then any remoting beyond there gets a big red ACCESS DENIED. Maybe you’ve tried CredSSP, but people say that isn’t safe. Read today’s post for a completely legit, secure, safe, and easy way to enable Kerberos double hop for PowerShell remoting.

The Problem

image

It’s a tale as old as time:

  • ServerA talks to ServerB
  • ServerB talks to ServerC
  • Access denied!

You would have better luck asking a cheerleader to the prom. We call this the kerberos double hop. Yeah, it’s like a dance.

The struggle is real. Just check out this forum post on PowerShell.org from last month. After many years of PowerShell remoting we are still searching for a secure method of passing credentials to that elusive ServerC.

Neo vs. the Architect

Many have come before you. Let’s look at some of the popular solutions for Kerberos double hop in PowerShell remoting:

Method Pros Cons Links
Grant access to the ServerC resource for the ServerB computer object. n/a It works for some other double hop use cases, but not PowerShell remoting.
CredSSP It works! It’s not totally secure.
Requires configuration of the client and server roles.
Accidental Sabotage: Beware of CredSSP
[MS-CSSP]: Credential Security Support Provider (CredSSP) Protocol – 5.1 Security Considerations for Implementers
PSSessionConfiguration using RunAs It works! Requires PSSessionConfiguration and RunAs credential password maintenance on every ServerB. Another solution to multi-hop PowerShell remoting
JEA – Just Enough Administration It works!
When using a virtual account there is no password maintenance.
Requires WMF 5.0 or above.
Requires role capability module and PSSessionConfiguration on every ServerB.
Just Enough Administration
Pass fresh credentials inside the Invoke-Command scriptblock ($using:cred) It works!
No special server configuration.
No Windows Server 2012 requirement.
Awkward code technique.
Easiest using WMF 3.0 or above. Also possible by using the WMF 2.0 syntax for passing arguments to a remote session.
See the very bottom of this article for a code sample.
Kerberos Constrained Delegation It may work if you can figure it out.
No special coding required.
Moves authority from the back-end resource owner to the front-end application owner.
Limited to one domain; cannot cross a trust.
Requires domain administrative rights to update objects and SPNs.
Not documented for PowerShell remoting.
Kerberos Unconstrained Delegation It works!
No special coding required.
It’s not totally secure.
Allows delegation of credentials with no control over where they get used.
Resource-Based Kerberos Constrained Delegation The magic answer.
No stored credentials.
Easy to configure.
No special domain access required.
Works across domains and forests.
No special coding required.
Requires Windows Server 2012 and above for most servers involved. See links at the bottom of the article.

 

Resource-Based Kerberos Constrained Delegation

Every release of Windows Server packs tons of new features, many that do not make big headlines. In my opinion this solution has been around four years now, and no one has uncovered its use for PowerShell remoting. I have researched this topic thoroughly, and I have not found anyone else online documenting this feature as a solution for PowerShell remoting.

Windows Server 2000 included Kerberos delegation (unconstrained). This allowed ServerB to delegate credentials anywhere else in the domain. Not good.

Windows Server 2003 modified this concept to constrained delegation, limiting delegation from ServerB to only designated service principal names (SPNs) on ServerC. This was much better, and it is common practice today. Many have struggled to get this working for PowerShell remoting, since it is not a documented solution.

Windows Server 2012 simplified the design by instead configuring the delegation on the computer object of ServerC, called resource-based delegation, specifying from whom it will receive delegated credentials. The same attribute can be set for user accounts and service accounts as well.

Resource-based Kerberos constrained delegation requires Windows Server 2012 or above for the servers involved, including at least one 2012 domain controller in each related domain. I am not going to include all of the details in this post, because the technology is well-documented. Read the links at the bottom of the article for all the particulars.

Show me some `Shell

This code for setting up the permissions requires a Windows box with the Windows Server 2012 Active Directory PowerShell RSAT available.

PS C:\> Add-WindowsFeature RSAT-AD-PowerShell

PS C:\> Import-Module ActiveDirectory

PS C:\> Get-Command -ParameterName PrincipalsAllowedToDelegateToAccount

CommandType Name                 ModuleName
----------- ----                 ----------
Cmdlet      New-ADComputer       ActiveDirectory
Cmdlet      New-ADServiceAccount ActiveDirectory
Cmdlet      New-ADUser           ActiveDirectory
Cmdlet      Set-ADComputer       ActiveDirectory
Cmdlet      Set-ADServiceAccount ActiveDirectory
Cmdlet      Set-ADUser           ActiveDirectory

Notice that some of the Active Directory cmdlets for Windows Server 2012 and above include a new parameter PrincipalsAllowedToDelegateToAccount. This parameter sets the Active Directory object attribute msDS-AllowedToActOnBehalfOfOtherIdentity. That attribute actually holds an access control list (ACL) determining who has permissions to delegate credentials to ServerC.

# Set up variables for reuse
$ServerA = $env:COMPUTERNAME
$ServerB = Get-ADComputer -Identity ServerB
$ServerC = Get-ADComputer -Identity ServerC

# Notice the StartName property of the WinRM Service: NT AUTHORITY\NetworkService
# This looks like the ServerB computer account when accessing other servers over the network.
Get-WmiObject Win32_Service -Filter 'Name="winrm"' -ComputerName $ServerB.name | fl *

The WinRM service by default runs as the NetworkService account. Therefore, we will allow ServerC to receive the computer object of ServerB for delegation.

# Grant resource-based Kerberos constrained delegation
Set-ADComputer -Identity $ServerC -PrincipalsAllowedToDelegateToAccount $ServerB

# Check the value of the attribute directly
$x = Get-ADComputer -Identity $ServerC -Properties msDS-AllowedToActOnBehalfOfOtherIdentity
$x.'msDS-AllowedToActOnBehalfOfOtherIdentity'.Access

# Check the value of the attribute indirectly
Get-ADComputer -Identity $ServerC -Properties PrincipalsAllowedToDelegateToAccount

The output of the ACL Access property shows a simple access control entry (ACE) for ServerB to delegate credentials to ServerC:

ActiveDirectoryRights : GenericAll
InheritanceType       : None
ObjectType            : 00000000-0000-0000-0000-000000000000
InheritedObjectType   : 00000000-0000-0000-0000-000000000000
ObjectFlags           : None
AccessControlType     : Allow
IdentityReference     : CONTOSO\ServerB$
IsInherited           : False
InheritanceFlags      : None
PropagationFlags      : None

Here is the one snag. The KDC has a 15 min SPN negative cache. If ServerB has already tried to talk to ServerC, then there is a negative cache entry. You need to clear the cache on ServerB using one of the following techniques:

  1. klist purge -li 0x3e7 (preferred and fastest method)
  2. Wait 15 minutes for the cache to clear automatically.
  3. Reboot ServerB.
Invoke-Command -ComputerName $ServerB.Name -Credential $cred -ScriptBlock {
    klist purge -li 0x3e7
}

or

Restart-Computer $ServerB.Name -Force -Wait -For WinRM

Once that step is complete we can successfully run code like this from ServerA through ServerB to ServerC:

# Capture a credential
$cred = Get-Credential Contoso\Alice

# Test kerberos double hop
Invoke-Command -ComputerName $ServerB.Name -Credential $cred -ScriptBlock {
    Test-Path \\$($using:ServerC.Name)\C$
    Get-Process lsass -ComputerName $($using:ServerC.Name)
    Get-EventLog -LogName System -Newest 3 -ComputerName $($using:ServerC.Name)
}

Note that the $using variable prefix allows ServerB to reference the $ServerC variable that lives in memory on ServerA. This makes the code entirely flexible. Just modify the $ServerB and $ServerC variables above with the computer names you want to use. Read more about $using in about_Remote_Variables.

You may want to allow multiple servers to delegate credentials to ServerC. In that case, set the parameter to an array of computer or user objects like this:

# Set up variables for each server
$ServerB1 = Get-ADComputer -Identity ServerB1
$ServerB2 = Get-ADComputer -Identity ServerB2
$ServerB3 = Get-ADComputer -Identity ServerB3
$ServerC  = Get-ADComputer -Identity ServerC

# Grant resource-based Kerberos constrained delegation
Set-ADComputer -Identity $ServerC `
    -PrincipalsAllowedToDelegateToAccount @($ServerB1,$ServerB2,$ServerB3)

According to this whitepaper include the domain controller FQDN in the Server parameter of the Get-ADComputer command to make it work across domains:

# For ServerC in Contoso domain and ServerB in other domain
$ServerB = Get-ADComputer -Identity ServerB -Server dc1.alpineskihouse.com
$ServerC = Get-ADComputer -Identity ServerC
Set-ADComputer -Identity $ServerC -PrincipalsAllowedToDelegateToAccount $ServerB

To undo the configuration, simply reset ServerC’s attribute to null.

Set-ADComputer -Identity $ServerC -PrincipalsAllowedToDelegateToAccount $null

A Practical Example

You have a jump box server that you connect to for daily administration. From that server you access all the other servers in your environment. The jump box server would be ServerB, so all the other servers in your environment (ServerC) would need ServerB allowed. Here is a code sample to query servers from an OU and set them all for resource-based Kerberos constrained delegation:

$ServerB = Get-ADComputer -Identity JumpBox
$Servers = Get-ADComputer -Filter {Name -ne $ServerB.Name} `
    -SearchBase 'OU=Servers,OU=NA,DC=contoso,DC=com' -SearchScope Subtree
ForEach ($ServerC in $Servers) {
    Set-ADComputer -Identity $ServerC -PrincipalsAllowedToDelegateToAccount $ServerB
}

Summary

Kerberos double hop for PowerShell remoting can now be solved with one simple cmdlet:

$ServerB = Get-ADComputer -Identity ServerB
$ServerC = Get-ADComputer -Identity ServerC
Set-ADComputer -Identity $ServerC -PrincipalsAllowedToDelegateToAccount $ServerB
# Then on ServerB: KLIST PURGE -LI 0x3e7

The benefits are many:

  • No PowerShell code modification.
  • No more SPNs for constrained delegation!
  • Credentials are not stored on ServerB.
  • Multiple domains and forests supported across trusts.
  • Easier setup and administration.
  • ServerA can now talk to ServerC through ServerB.

Once again the world is a happy place. Now go try it for yourself. Use the comment area below for feedback. Let me know how it goes.

Resource-Based Kerberos Constrained Delegation Links

What’s New in Kerberos Authentication
Resource-based constrained delegation across domains and forest
https://technet.microsoft.com/en-us/library/hh831747.aspx

How Windows Server 2012 Eases the Pain of Kerberos Constrained Delegation, Part 1
http://windowsitpro.com/security/how-windows-server-2012-eases-pain-kerberos-constrained-delegation-part-1
“Constrained delegation in Server 2012 introduces the concept of controlling delegation of service tickets using a security descriptor rather than an allow list of SPNs. This change simplifies delegation by enabling the resource to determine which security principals are allowed to request tickets on behalf of another user.”
“Resource-based constrained delegation functions correctly regardless of domain functional level and number of domain controllers (DCs) running a version of Windows Server prior to Server 2012, provided you have at least one Server 2012 DC in the same domain as the front-end server and one Server 2012 DC in the domain hosting the back-end server.”

How Windows Server 2012 Eases the Pain of Kerberos Constrained Delegation, Part 2
http://windowsitpro.com/security/how-windows-server-2012-eases-pain-kerberos-constrained-delegation-part-2

Understanding Kerberos Constrained Delegation for Azure Active Directory Application Proxy Deployments with Integrated Windows Authentication
http://aka.ms/kcdpaper

[MS-ADA2]: Active Directory Schema Attributes M
2.210 Attribute msDS-AllowedToActOnBehalfOfOtherIdentity
https://msdn.microsoft.com/en-us/library/hh554126.aspx
“This attribute is used for access checks to determine if a requestor has permission to act on the behalf of other identities to services running as this account.”

[MS-SFU]: Kerberos Protocol Extensions: Service for User and Constrained Delegation Protocol
1.3.2 S4U2proxy
https://msdn.microsoft.com/en-us/library/cc246079.aspx

Resource Based Kerberos Constrained Delegation
https://blog.kloud.com.au/2013/07/11/kerberos-constrained-delegation/

Remote Administration Without Constrained Delegation Using PrincipalsAllowedToDelegateToAccount
https://blogs.msdn.microsoft.com/taylorb/2012/11/06/remote-administration-without-constrained-delegation-using-principalsallowedtodelegatetoaccount/

 

image

When All Else Fails… $using:cred

If you still have no Windows Server 2012 domain controllers in your environment then you can use this technique:

# This works without delegation, passing fresh creds
# Note $Using:Cred in nested request
$cred = Get-Credential Contoso\Administrator
Invoke-Command -ComputerName ServerB -Credential $cred -ScriptBlock {
    hostname
    Invoke-Command -ComputerName ServerC -Credential $Using:cred -ScriptBlock {hostname}
}

This works, because the $using:cred passes a fresh copy of the credential variable into the remoting session without storing it anywhere. You could also swap out the Invoke-Command cmdlets with Enter-PSSession. The only requirement is WMF 3.0 or above on your servers.

Edit 8/31/16: Thanks to fellow PFE Martin Schvartzman for the KLIST PURGE syntax!
Edit 9/26/16: Added a code sample for the $using:cred alternative.
Edit 12/5/16: After much researcher internally we have concluded that this technique does not support double-hop for WinRM-based commands (Invoke-Command, Enter-PSSession, Get-CimInstance, etc.). I plan to release more details on this later.

Use the new PowerShell cmdlet Convert-String to parse email addresses

$
0
0

image_thumb[9]Tired of hacking away at RegEx and string functions to parse text? This post is for you!

New toys

PowerShell 5.x includes a number of new features. One of the lesser-known and incredibly powerful is the string conversion set of cmdlets. The names are very similar. Check out how Get-Help describes them:

PS C:\> Get-Help Convert*-String | Format-Table Name,Synopsis -AutoSize

Name               Synopsis
----               --------
Convert-String     Formats a string to match examples.
ConvertFrom-String Extracts and parses structured objects from string content.

Convert-String

I will admit that doesn’t sound very interesting on first glance. But check out what they can do! Let’s start with a simple example of Convert-String:

'Alice Alpha <alice.alpha@contoso.com>;' |
Convert-String -Example 'Alice Alpha <alice.alpha@contoso.com>;=Alice,Alpha,alice.alpha@contoso.com'

The -Example parameter is a string set up as SampleData=DesiredFormat. The above example will parse Alice’s name and email into clean CSV data. It doesn’t always have to be CSV, but that is what I need for this use case.

Alice,Alpha,alice.alpha@contoso.com

1up

Now let’s take a list of email addresses pasted from Outlook. Notice that we pipe them to –Split, giving us an array for string conversion split on new lines:

$Emails = @"
Alice Alpha <alice.alpha@contoso.com>;
Bob Beta <bob.beta@contoso.com>;
Charlie Charles <charlie.charles@contoso.com>;
Doug Delta <doug.delta@contoso.com>
"@ -Split "`n"

$Emails |
Convert-String -Example 'Alice Alpha <alice.alpha@contoso.com>;=Alice,Alpha,alice.alpha@contoso.com'

This code turns a list of email addresses into nice CSV data. Because the addresses are all formatted similarly, the one example of Alice shows how to parse all the lines.

Alice,Alpha,alice.alpha@contoso.com
Bob,Beta,bob.beta@contoso.com
Charlie,Charles,charlie.charles@contoso.com
Doug,Delta,doug.delta@contoso.com

CSV baby!

Let’s add ConvertFrom-CSV to include some headers.

$Emails = @"
Alice Alpha <alice.alpha@contoso.com>;
Bob Beta <bob.beta@contoso.com>;
Charlie Charles <charlie.charles@contoso.com>;
Doug Delta <doug.delta@contoso.com>
"@ -Split "`n"

$Emails |
Convert-String -Example 'Alice Alpha <alice.alpha@contoso.com>;=Alice,Alpha,alice.alpha@contoso.com' |
ConvertFrom-Csv -Header 'FirstName','LastName','Email'

Now we have clean PowerShell object output for a list of email addresses pasted from Outlook. Cool!

FirstName LastName Email
--------- -------- -----
Alice     Alpha    alice.alpha@contoso.com
Bob       Beta     bob.beta@contoso.com
Charlie   Charles  charlie.charles@contoso.com
Doug      Delta    doug.delta@contoso.com

Convert-String works with a single parsing example. If you have a variety of complex patterns to parse, then use ConvertFrom-String instead. We will look at that in tomorrow’s post.

Your turn…

I decided to keep this post short and leave other things for you to discover with the cmdlet. I have shown you one way to use it. There is more! Get-Help is your friend.

Now take this and go parse some of your own flat text use cases. Use the comments below to share your challenges and victories. Enjoy!

Use the new PowerShell cmdlet ConvertFrom-String to parse KLIST Kerberos ticket output

$
0
0

Tired of hacking away at RegEx and string functions to parse text? This post is for you!

ConvertFrom-String

imageIn yesterday’s post we reviewed a simple example of the new PowerShell 5.x Convert-String cmdlet. Today we are going to study a complex example with ConvertFrom-String. This cmdlet was first documented here in a PowerShell team blog post. To make a long story short, the Microsoft Research team invented some fuzzy logic for parsing large quantities of text using sample data. The technology learns and adapts as it parses. If the output does not look correct, you simply add more examples demonstrating the variation that was not matched.

The trouble with KLIST

I was doing some Kerberos research lately, and I wanted to parse the output of KLIST to be more PowerShell friendly. KLIST displays current Kerberos tickets on a machine, but it is flat text. We will use ConvertFrom-String to turn it into beautiful, sortable, filterable object data like this in Out-Gridview:

image

First, let’s take a look at a sample of KLIST output:

Current LogonId is 0:0x3f337

Cached Tickets: (12)

#0>	Client: Administrator @ CONTOSO.COM
	Server: krbtgt/CONTOSO.COM @ CONTOSO.COM
	KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
	Ticket Flags 0x60a10000 -> forwardable forwarded renewable pre_authent name_canonicalize
	Start Time: 8/29/2016 16:06:22 (local)
	End Time:   8/30/2016 2:06:21 (local)
	Renew Time: 9/5/2016 16:06:21 (local)
	Session Key Type: AES-256-CTS-HMAC-SHA1-96
	Cache Flags: 0x2 -> DELEGATION
	Kdc Called: 2012R2-DC.contoso.com

#1>	Client: Administrator @ CONTOSO.COM
	Server: krbtgt/CONTOSO.COM @ CONTOSO.COM
	KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
	Ticket Flags 0x40e10000 -> forwardable renewable initial pre_authent name_canonicalize
	Start Time: 8/29/2016 16:06:21 (local)
	End Time:   8/30/2016 2:06:21 (local)
	Renew Time: 9/5/2016 16:06:21 (local)
	Session Key Type: AES-256-CTS-HMAC-SHA1-96
	Cache Flags: 0x1 -> PRIMARY
	Kdc Called: 2012R2-DC

#2>	Client: Administrator @ CONTOSO.COM
	Server: host/2012R2-MS.contoso.com @ CONTOSO.COM
	KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
	Ticket Flags 0x40a10000 -> forwardable renewable pre_authent name_canonicalize
	Start Time: 8/29/2016 16:12:25 (local)
	End Time:   8/30/2016 2:06:21 (local)
	Renew Time: 9/5/2016 16:06:21 (local)
	Session Key Type: AES-256-CTS-HMAC-SHA1-96
	Cache Flags: 0
	Kdc Called: 2012R2-DC.contoso.com
...
...

One line of code!

The data contains multiple objects with multiple properties. Unfortunately that is all plain text. To parse this using regular expressions or string functions would be time-consuming and error-prone. Here is the ConvertFrom-String syntax used to produce the screenshot at the top of the article:

klist | ConvertFrom-String -TemplateFile .\template.txt | Out-GridView

Template magic

Wow! Are you kidding?! Nope. That’s it. But… wait… what’s in that template.txt file? Ah. That is the magic. Let’s take a look:

Current LogonId is 0:0xb4ffc69

Cached Tickets: (4)

#{[int]ID*:0}>	Client: {Client:Administrator @ CONTOSO.COM}
	Server: {Server:krbtgt/CONTOSO.COM @ CONTOSO.COM}
	KerbTicket Encryption Type: {KerbTicketEncryptionType:AES-256-CTS-HMAC-SHA1-96}
	Ticket Flags {TicketFlags:0x60a10000} -> {TicketFlagsEnum:forwardable forwarded renewable pre_authent name_canonicalize}
	Start Time: {[datetime]StartTime:8/29/2016 16:06:22} (local)
	End Time:   {[datetime]EndTime:8/30/2016 2:06:21} (local)
	Renew Time: {[datetime]RenewTime:9/5/2016 16:06:21} (local)
	Session Key Type: {SessionKeyType:AES-256-CTS-HMAC-SHA1-96}
	Cache Flags: {CacheFlags:0x1} -> {CacheFlagsEnum:PRIMARY}
	Kdc Called: {KdcCalled:2012R2-DC.contoso.com}

#{[int]ID*:1}>	Client: {Client:Administrator @ CORP.CONTOSO.COM}
	Server: {Server:krbtgt/CONTOSO.COM @ CONTOSO.COM}
	KerbTicket Encryption Type: {KerbTicketEncryptionType:AES-256-CTS-HMAC-SHA1-96}
	Ticket Flags {TicketFlags:0x40e10000} -> {TicketFlagsEnum:forwardable renewable initial pre_authent name_canonicalize}
	Start Time: {[datetime]StartTime:8/29/2016 16:06:21} (local)
	End Time:   {[datetime]EndTime:8/30/2016 2:06:21} (local)
	Renew Time: {[datetime]RenewTime:9/5/2016 16:06:21} (local)
	Session Key Type: {SessionKeyType:AES-256-CTS-HMAC-SHA1-96}
	Cache Flags: {CacheFlags:0x2} -> {CacheFlagsEnum:DELEGATION}
	Kdc Called: {KdcCalled:2012R2-DC.contoso.com}

#{[int]ID*:2}>	Client: {Client:Administrator @ CORP.NA.ALPINESKIHOUSE.COM}
	Server: {Server:host/2012R2-MS.contoso.com @ CONTOSO.COM}
	KerbTicket Encryption Type: {KerbTicketEncryptionType:AES-256-CTS-HMAC-SHA1-96}
	Ticket Flags {TicketFlags:0x40a10000} -> {TicketFlagsEnum:forwardable renewable pre_authent name_canonicalize}
	Start Time: {[datetime]StartTime:8/29/2016 1:12:25} (local)
	End Time:   {[datetime]EndTime:8/30/2016 2:06:21} (local)
	Renew Time: {[datetime]RenewTime:9/5/2016 1:06:21} (local)
	Session Key Type: {SessionKeyType:AES-256-CTS-HMAC-SHA1-96}
	Cache Flags: {CacheFlags:0}
	Kdc Called: {KdcCalled:2012R2-DC}

#{[int]ID*:3}>	Client: {Client:Administrator @ CONTOSO.COM}
	Server: {Server:RPCSS/2012R2-MS.contoso.com @ CONTOSO.COM}
	KerbTicket Encryption Type: {KerbTicketEncryptionType:RSADSI RC4-HMAC(NT)}
	Ticket Flags {TicketFlags:0x40a10000} -> {TicketFlagsEnum:forwardable renewable pre_authent name_canonicalize}
	Start Time: {[datetime]StartTime:12/29/2016 16:12:25} (local)
	End Time:   {[datetime]EndTime:12/30/2016 12:06:21} (local)
	Renew Time: {[datetime]RenewTime:12/5/2016 16:06:21} (local)
	Session Key Type: {SessionKeyType:RSADSI RC4-HMAC(NT)}
	Cache Flags: {CacheFlags:0}
	Kdc Called: {KdcCalled:2012R2-DC.contoso.com}

To create the parsing template we begin by capturing the KLIST output to a text file like this:

KLIST > template.txt

Let’s break down the formatting in the template file:

  • Basic property parsing looks like this: {[datatype]PropertyName:DATA}. To extract meaningful data from flat text, you surround sample output data values with this syntax.
  • The datatype is optional, if you want to use strings for everything. I chose to use [int] and [datetime] for intelligent sorting and filtering of property data.
  • For multi-object parsing in a file like this, the first property on the object gets the asterisk * after the property name. In this case I chose ID to indicate a new record.

For each data instance in the template file we add some formatting to identify the properties we want to extract. We do not need to keep every instance of the certificates in the list, only enough to demonstrate different sample values. Study the example template above to find these differences:

  • Cache Flags
  • Cache Flags Enum (does not appear in every record)
  • KerbTicket Encryption Type
  • Session Key Type
  • Ticket Flags
  • Dates (single-digit vs. double-digit days/months)
  • Server short name vs. FQDN (fully qualified domain name)
  • FQDNs of varying dotted patterns
  • Etc.

Mash the easy button

Does that template.txt look difficult? It might. But it is actually not that bad, and it is MUCH easier than trying to write a RegEx or string functions to parse this. Actually, the fuzzy logic behind the cmdlet does exactly that. It studies each sample to identify differences (string length, spaces, capitalization, etc.) and then dynamically generates parsing code. Some consider this to be like AI (artificial intelligence) or ML (machine learning).

The template above took a couple hours of tweaking and experimenting. It works 95% of the time. Your mileage may vary. For example, you may need to tweak the template for international date formats or different type values.

Your turn…

I decided to keep this blog post short and leave other things for you to discover with the cmdlet. I have shown you one way to use it. There is more! Get-Help is your friend.

Now take this and go parse some of your own flat text use cases. Use the comments below to share your challenges and victories. Enjoy!

Gnarly Innards: How to live debug PowerShell DSC configurations without using Enable-DSCDebug

$
0
0

17_ctraltdelThe Problem

Have you ever needed to debug a PowerShell Desired State Configuration that appeared to be hanging when it was applying? At that point it’s a little too late to run Enable-DscDebug. Here’s how to debug it anyway…

The Solution

On the box applying the active configuration you can see the LCM is busy. Notice the LCMState and LCMStateDetail properties.

PS C:\> Get-DscLocalConfigurationManager

ActionAfterReboot              : ContinueConfiguration
AgentId                        : 7DF72A3A-9AEF-11E6-80BB-00155D67460E
AllowModuleOverWrite           : False
CertificateID                  :
ConfigurationDownloadManagers  : {}
ConfigurationID                :
ConfigurationMode              : ApplyOnly
ConfigurationModeFrequencyMins : 15
Credential                     :
DebugMode                      : {NONE}
DownloadManagerCustomData      :
DownloadManagerName            :
LCMCompatibleVersions          : {1.0, 2.0}
LCMState                       : Busy
LCMStateDetail                 : LCM is a applying an existing configuration.
LCMVersion                     : 2.0
StatusRetentionTimeInDays      : 10
PartialConfigurations          :
RebootNodeIfNeeded             : True
RefreshFrequencyMins           : 30
RefreshMode                    : PUSH
ReportManagers                 : {}
ResourceModuleManagers         : {}
PSComputerName                 :

To debug it we need to find out which process is applying the configuration. DSC configurations run in the WmiPrvSE process, but there are usually multiple instances of this process at any given time. We want the one with the DSC AppDomainName.

PS C:\> (Get-Process WmiPrvSE).Id | ForEach-Object {Get-PSHostProcessInfo -Id $_ | Where-Object AppDomainName -eq 'DscPsPluginWkr_AppDomain'}

ProcessName ProcessId AppDomainName
----------- --------- -------------
WmiPrvSE         3536 DscPsPluginWkr_AppDomain

Then we enter that process for debugging. After listing the runspaces you will usually debug #1.

PS C:\> Enter-PSHostProcess -Id 3536 -AppDomainName DscPsPluginWkr_AppDomain
[Process:3536]: PS C:\Windows\system32> Get-Runspace

 Id Name            ComputerName    Type          State         Availability
 -- ----            ------------    ----          -----         ------------
  1 Runspace1       localhost       Local         Opened        Busy
  2 Runspace2       localhost       Local         Opened        Available
 89 RemoteHost      localhost       Local         Opened        Busy

[Process:3536]: PS C:\Windows\system32> Debug-Runspace -Id 1

Now use the traditional PowerShell command line debugging techniques (? for menu). In my case I was debugging the xWaitForADDomain resource which has a sleep timer in it. At this point I had to wait for the timer to expire on the current iteration before the debug prompt would appear. As the hackers say in the movies: “I’m in!”

[DBG]: [Process:3536]: [Runspace1]: PS C:\Windows\system32>> ?

 s, stepInto         Single step (step into functions, scripts, etc.)
 v, stepOver         Step to next statement (step over functions, scripts, etc.)
 o, stepOut          Step out of the current function, script, etc.

 c, continue         Continue operation
 q, quit             Stop operation and exit the debugger
 d, detach           Continue operation and detach the debugger.

 k, Get-PSCallStack  Display call stack

 l, list             List source code for the current script.
                     Use "list" to start from the current line, "list "
                     to start from line , and "list  " to list
                     lines starting from line

              Repeat last command if it was stepInto, stepOver or list

 ?, h                displays this help message.


For instructions about how to customize your debugger prompt, type "help about_prompt".

You can use Get-Variable to see a list of all the variable in scope as the code is executing. Use ‘l’ to list the code and see where you are in the current execution. Use ‘s’, ‘v’, ‘o’ to step through and find your problem. Once you have analyzed your code, you can either use ‘d‘ to detach and let it keep running or ‘q‘ to stop the configuration completely and exit the debugger.

[DBG]: [Process:3536]: [Runspace1]: PS C:\Windows\system32>> d
[Process:3536]: PS C:\Windows\system32> Exit-PSHostProcess

There you go. You have now seen the gnarly innards of a live DSC configuration running on your box. I hope you do not need this trick very often, but now you know.

More Information

Read more about debugging PowerShell DSC configurations and resources:

Debugging PowerShell DSC Class Resources – Great article that teaches everything we did above.
https://blogs.msdn.microsoft.com/powershell/2016/03/14/debugging-powershell-dsc-class-resources/

PowerShell Runspace Debugging: Part 1 – More good background information.
https://blogs.msdn.microsoft.com/powershell/2015/09/08/powershell-runspace-debugging-part-1/

Get-Help about_Debuggers – Learn more about PowerShell command line debugging.
https://technet.microsoft.com/en-us/library/2b2ce8b3-f881-4528-bd30-f453dea06755

What’s New in PowerShell v5 – Watch the module 4 video of PowerShell MVP Kirk Munro explaining debugging
http://aka.ms/mvaps5


How to run a PowerShell script against multiple Active Directory domains with different credentials

$
0
0

05_collageI was working with a customer recently who needed to execute the same script against servers in different Active Directory domains. They had administrative privileges in each domain, but each domain used a different account. You could apply this same scenario to running one query against domain controllers in different domains. Today we’ll explore one way to do that.

Multiple Credentials

A while back I stumbled onto this handy blog post by Jaap Brasser, a PowerShell MVP from the Netherlands. He was using a hash table to store multiple credentials in a script, and then cache them to disk securely using Export-CliXML. The XML export is a quick way to dump the secure string passwords to disk for later re-use. This has been a popular technique for several years now, but he is the first one I saw doing this with a hash table of credentials. Nice touch! In this post I am building on his technique.

Passwords on disk?!

Many people have blogged about securely storing PowerShell credentials for reuse later. There are many techniques, even Azure Key Vault. However, the most common technique out-of-the-box is with secure strings. I do not have time to rehash these topics here. For more information check out Get-Help for these cmdlets: Get-Credential, ConvertFrom-SecureString, ConvertTo-SecureString.

The main point to understand here is that PowerShell encrypts secure string passwords by default using the DPAPI. This encryption is tied to one user on one computer. If you export credentials to a file, then you can only read them on the computer where the file was generated and with the same user account.

Managing Multiple Credentials

Many customers have multiple-domain Active Directory environments and need a way to manage all of those credentials in a single script. Think about the following use cases:

  • Run the same query against every domain controller in three domains or forests
  • Run the same command against 100 servers residing in 10 different domains

Some people may have simply run the same script multiple times, prompting for credentials of each domain and targeting only those servers. Then repeat that for each domain. This is inefficient and produces multiple data sets to be joined at the end for one view of the output.

To do this efficiently and securely is an advanced scripting challenge.

One Solution

As I approached this problem I broke it down into the following steps:

  • Store the target server FQDNs in an array (from file, AD query, etc.)
  • Parse out the unique domain names from the FQDNs
  • Prompt once for credentials of each unique domain
  • Store the credentials in a hash table
  • Export the credential hash table to XML for reuse later
  • Import the credentials from XML (for subsequent runs of the script)
  • Using a loop, pass each server FQDN and respective domain credential to Invoke-Command

Caveat Emptor (“Buyer Beware”)

A comment on Jaap’s blog post cautions against storing highly privileged account credentials in an encrypted secure string using Export-CliXML. Anyone with access to the one account on the one computer used to encrypt the secure string would be able to retrieve all the different domain credentials stored there. They could decrypt all the passwords into plain text! This is a valid concern. However, regardless of how you store the credentials they will all be available to the one user account while the script is running on this one server. If you choose to run any script with multiple credentials, then this concern will always exist. At that point it is an HR issue making sure your staff is trustworthy.

If you choose to store credentials in a file, then you must secure it appropriately and know the risks even when they are encrypted. With that warning we will proceed.

Clever Credential Controls

Here is a sample script for implementing multiple credentials:

Function Get-DomainCreds {
[CmdletBinding()]
Param(
    [Parameter(
        Mandatory=$true,
        ParameterSetName='Fresh'
    )]
    [ValidateNotNullOrEmpty()]
    [string[]]
    $Domain,
    [Parameter(
        Mandatory=$true,
        ParameterSetName='File'
    )]
    [Parameter(
        Mandatory=$true,
        ParameterSetName='Fresh'
    )]
    [ValidateNotNullOrEmpty()]
    [string]
    $Path
)

    If ($PSBoundParameters.ContainsKey('Domain')) {

        # http://www.jaapbrasser.com/quickly-and-securely-storing-your-credentials-powershell/
        $Creds = @{}
        ForEach ($DomainEach in $Domain) {
            $Creds[$DomainEach] = Get-Credential `
                -Message "Enter credentials for domain $DomainEach" `
                -UserName "$DomainEach\username"
        }
        $Creds | Export-Clixml -Path $Path

    } Else {

        $Creds = Import-Clixml -Path $Path

    }

    Return $Creds
}

Function Split-FQDN {
Param(
    [string[]]$FQDN
)
    ForEach ($Server in $FQDN) {

        $Dot = $Server.IndexOf('.')
        [pscustomobject]@{
            FQDN     = $Server
            Hostname = $Server.Substring(0,$Dot)
            Domain   = $Server.Substring($Dot+1)
        }

    }
}


# Array of server FQDNs from your favorite data source
$Servers = 'server1.contoso.com','dc1.alpineskihouse.com',`
    'dc2.wideworldimporters.com','dc3.contoso.com'
# Take a server list of FQDNs and separate out the domain and hostname
$ServerList = Split-FQDN -FQDN $Servers

# Extract the unique domain names
# ONLY THE FIRST RUN: Get credentials for each domain
$Domains = $ServerList | Select-Object -ExpandProperty Domain -Unique
$DomCreds = Get-DomainCreds -Domain $Domains -Path C:\deploy\creds.xml

# LATER: Get credentials for each domain from the XML file
$DomCreds = Get-DomainCreds -Path C:\deploy\creds.xml

ForEach ($Server in $ServerList) {

    Invoke-Command -ComputerName $Server.FQDN `
        -Credential $DomCreds[$Server.Domain] -ScriptBlock {

        "Hello from $(hostname)"

    }

}

The clever part here is using the domain portion of the FQDN as the hash table key to retrieve the domain-specific credential for each server FQDN in the list.

Insert your own code inside the ScriptBlock parameter of Invoke-Command. Or use the FilePath parameter instead to run the same script on each remote server.

If you do not want to store the credentials in a file, then comment out the Export-CliXML line in the Get-DomainCreds function. You will need to enter the credentials manually each time you run the script if that is your choice.

Now you can schedule this to run unattended using the credentials in the XML file. Note that you must run the script to build the credential XML file under the same user account for the scheduled task.

Here is an example of executing one command across multiple domains:

# Query a list of domain controllers using stored credentials (include functions above)
# List the Domain Admin group membership for all domains
$Servers = 'dc1.alpineskihouse.com',`
    'dc2.wideworldimporters.com','dc3.contoso.com'
$ServerList = Split-FQDN -FQDN $Servers
$DomCreds = Get-DomainCreds -Path C:\deploy\creds.xml
ForEach ($Server in $ServerList) {
    '*' * 40
    $Server.Domain
    Invoke-Command -ComputerName $Server.FQDN `
        -Credential $DomCreds[$Server.Domain] -ScriptBlock {
        Get-ADGroupMember -Identity 'Domain Admins' |
            Select-Object -ExpandProperty distinguishedName
    }
}

You could just as easily loop through Get-ADObject queries passing a unique Server and Credential parameter instead of using Invoke-Command. But it would not be any fun if I wrote all the code for you.

Summary

This is a common scenario, so I wanted to offer a solution using built-in PowerShell features. Now you have one technique for running the same code under multiple credentials against servers in multiple Active Directory domains.

How have you solved this challenge in your environment? How can you use this technique? Comments welcome.

2017 New Years PowerShell DevOps Study List

$
0
0

10_geekmugMicrosoft: from “know-it-all” to “learn-it-all”

In a recent interview Satya Nadella mentioned the learn-it-all mindset. This is certainly true in the world of PowerShell. We are so far beyond “just a scripting language” now.

Wow! Have you been paying attention to PowerShell this year? So many big announcements! Today’s post is a crazy link list of 2016 PowerShell news, whitepapers and projects for your study list in 2017. Warning: This may seem a bit random. It is a massive amount of info, and I’m sure I missed some things. Not all of these are new topics, but they really gained traction this last year.

The One Link

This is the one link that I start every PowerShell conversation with: http://microsoft.com/powershell. Get the docs, download WMF, submit feedback, read blogs, and more. It’s all there.

Christmas movies or PowerShell videos?

PowerShell is a key component to making DevOps a reality on the Windows platform (now any platform). This graphic comes from Michael Greene’s WinOps 2016 presentation. Some of these community project names were new to me, so I compiled a list of links where we can find more information.

image

Release Pipeline Model

In 2016 Michael Greene and Steven Murawski did a road show with the Release Pipeline Model whitepaper. Check out all of these resources and appearances:

Release Pipeline Model Whitepaper Download

http://aka.ms/trpm

http://aka.ms/thereleasepipelinemodel

http://download.microsoft.com/download/C/4/A/C4A14099-FEA4-4CB3-8A8F-A0C2BE5A1219/The%20Release%20Pipeline%20Model.pdf

Slides for RPM talks

https://github.com/mgreenegit/slides/tree/master/TRPM

Ignite – Gain insight into a Release Pipeline Model

https://myignite.microsoft.com/videos/22116

https://www.youtube.com/watch?v=7L1-Kawajss

PowerShell and DevOps Global Summit Presentation April 2016 – First public presentation of the whitepaper

https://www.youtube.com/watch?v=bRd0XiMIRMs

WinOps 2016 Presentation

https://channel9.msdn.com/Events/WinOps/WinOps-Conf-2016/The-Release-Pipeline-Model

WinOps 2016 Interview

https://channel9.msdn.com/Events/WinOps/WinOps-Conf-2016/Michael-Greene-on-DevOps?ocid=relatedsession

PowerScripting Podcast 315 Release Pipeline Model

https://powershell.org/2016/08/15/episode-315-powerscripting-podcast-michael-greene-microsoft-and-steven-murawski-chef-on-the-release-pipeline-model/

RunAs Radio 469 Release Pipeline Model

http://www.runasradio.com/default.aspx?ShowNum=469

TechNetRadio

https://channel9.msdn.com/shows/technet+radio/tnr1666

Code Channels Interview

https://www.codechannels.com/video/microsoft/devops/13-the-release-pipeline-model-transform-it-ops-with-devops-practices/

https://channel9.msdn.com/Shows/DevOps-Dimension/13–The-Release-Pipeline-Model-Transform-IT-Ops-with-DevOps-Practices?ocid=player

Release Pipeline Tools Walk-Through Blog

https://devblackops.io/building-a-simple-release-pipeline-in-powershell-using-psake-pester-and-psdeploy/

Pester

Wyatt – Testing in PowerShell

https://www.youtube.com/watch?v=SftZCXG0KPA

Wyatt – Beyond Syntax: Types of Testing with Pester

https://www.youtube.com/watch?v=0fFrWIxVDl0

Blender – Test-Driven Development

https://www.youtube.com/watch?v=jvvh9cpD_LM

Pester YouTube Playlist

https://www.youtube.com/watch?v=chN5BZUmyQ0&list=PLmUhughzLLXiv7A-8DESD5_wwM6hIvrjT

Mississippi PS UG Presentation

https://youtu.be/o4ihc7atwYQ?list=PLmUhughzLLXiv7A-8DESD5_wwM6hIvrjT

PSake

https://twitter.com/psake_build

https://github.com/psake/psake

http://psake.readthedocs.io/en/latest/

https://www.powershellgallery.com/packages/psake/4.6.0

https://marketplace.visualstudio.com/items?itemName=qetza.psake

Git, Plaster, PSDeploy, PoshSpec, etc.

Warren Frame on Continuous Deployment with PowerShell

https://www.youtube.com/watch?v=jKLf1KjYhTM

Warren Frame Git Crash Course

https://www.youtube.com/watch?v=wmPfDbsPeZY

PoshSpec – Chris Hunt author

https://www.youtube.com/watch?v=IIlbPbXga0M

David Wilson – PowerShell projects with Plaster

https://www.youtube.com/watch?v=0OTLYWSdbtA

PSDeploy

http://ramblingcookiemonster.github.io/PSDeploy-Take-Two/

Invoke-Build

https://github.com/nightroman/Invoke-Build

Lability
https://channel9.msdn.com/Blogs/PSDEVOPSSIG/PSDEVOPSSIGEventLability-Demo-w-Iain-Brigton
https://blog.kilasuit.org/2016/04/13/building-a-lab-using-hyper-v-and-lability-the-end-to-end-example/
https://www.powershellgallery.com/packages/Lability/0.10.1

Visual Studio Code

VSCode has taken the world by storm, and it is a terrific PowerShell editor. It works on Windows, Linux, and Mac. And it’s free!

http://code.visualstudio.com/

https://github.com/PowerShell/vscode-powershell

https://github.com/PowerShell/vscode-powershell/blob/master/CHANGELOG.md

Open Source PowerShell & 10th Anniversary

Jeffrey and team finally did it. Now you can run it on Linux and Mac. You can even view and contribute to the source code.

https://channel9.msdn.com/Blogs/hybrid-it-management/PowerShell-on-Linux-and-Open-Source

https://blogs.msdn.microsoft.com/powershell/2016/08/18/powershell-on-linux-and-open-source-2/

https://blogs.msdn.microsoft.com/powershell/2016/08/17/windows-powershell-is-now-powershell-an-open-source-project-with-linux-support-how-did-we-do-it/

https://github.com/PowerShell/PowerShell

https://blogs.msdn.microsoft.com/powershell/2016/11/08/join-the-powershell-10th-anniversary-celebration/

https://channel9.msdn.com/Events/PowerShell-Team/PowerShell-10-Year-Anniversary

The PowerShell Team even has their own YouTube channel now:

https://www.youtube.com/channel/UCMhQH-yJlr4_XHkwNunfMog

For Your DevOps Book Shelf

Finally, for many people DevOps on any platform begins with reading The Phoenix Project. (I chose the 11 hour audiobook.) This year Gene Kim and team released a sequel The DevOps Handbook. Wow. This book has gold on every page. I recommend it for any organization going through the DevOps transformation.

Learn All The Things

There is no shortage of new material in the world of PowerShell and DevOps. Pick a topic and dive in. I hope you enjoy these links.

Pro Tip: PowerShell DSC Events to Monitor

$
0
0

01_blivitThe Problem

I need to monitor PowerShell DSC health on all of my nodes. But I do not want to wait for every possible event to happen in production to catch it and add it to my monitoring event list.

The Options

There are many options for monitoring PowerShell Desired State Configuration (DSC) status on your Windows nodes:

  • DSC reporting server
  • Get-DSCConfigurationStatus / Test-DSCConfiguration
  • xDscDiagnostics
  • OMS / Azure Automation DSC
  • Harvest and parse the status files under C:\Windows\System32\Configuration\ConfigurationStatus\
  • Event logs (which logs and events to capture?)
  • Windows Event Forwarding
  • Enterprise tools: Splunk, Nagios, SCOM, etc.

I am not saying any one of these options is better than the other. Some would certainly require more work.

One of the easiest options is to simply monitor the Windows event log on your DSC nodes. (While DSC is now available on other platforms, this tip is for Windows nodes.)

The Solution

Every company should already have an enterprise monitoring solution to collect server events centrally and alert on them.

This sweet little snippet below will give you a list of every possible event so that you don’t have to wait for them to happen in production to catch the ID to add to your monitoring solution.

(Get-WinEvent -ListProvider Microsoft-Windows-DSC).Events |
    Select-Object `
        @{Name='Log'       ;Expression={$_.LogLink.LogName}},   `
        @{Name='LevelValue';Expression={$_.Level.Value}},       `
        @{Name='LevelName' ;Expression={$_.Level.DisplayName}}, `
        Id, Description, Template |
    Out-GridView -Title 'DSC Client Events'

Now you can see every possible Information, Warning, and Error event for the Operational, Analytic, and Debug logs in the Microsoft-Windows-DSC provider. It also shows you what all of the place-holder values are in the error message. Here is a clipping of the output:

image

You could even take this list and pipe it into some code to automatically generate an event log import template file for your monitoring tool of choice.

I can’t find the Analytic and Debug logs.

By default the Analytic and Debug logs are turned off. You can enable them using either wevtutil.exe or xDscDiagnostics\Update-xDscEventLogStatus.

But wait, there’s more!

There is more than one provider for DSC event logs, especially if you are wanting to monitor pull server events as well. Use this snippet of code to list the same event information above for any possible DSC event log on your server.

$Providers = Get-WinEvent -ListLog *DSC*, *DesiredState* -Force |
    Select-Object -Unique -ExpandProperty OwningProviderName
$DSCEvents = ForEach ($Provider in $Providers) {
    (Get-WinEvent -ListProvider $Provider).Events |
        Select-Object `
            @{Name='Log'       ;Expression={$_.LogLink.LogName}},   `
            @{Name='LevelValue';Expression={$_.Level.Value}},       `
            @{Name='LevelName' ;Expression={$_.Level.DisplayName}}, `
            Id, Description, Template
}
$DSCEvents | Out-GridView -Title 'DSC Events'

If you would like more information on how this code snippet works or how to filter out specifics of the event message fields, then go read this popular previous post (and the sequel post) that explains events, schemas, and XML in PowerShell.

Happy Hunting

Now those of us who insist on everything being complete and orderly can put our minds at ease. You now have a way to list every possible DSC event log entry and decide which ones you want to monitor. Happy hunting.

Compare Group Policy (GPO) and PowerShell Desired State Configuration (DSC)

$
0
0

14_floppyWhat is the difference between Group Policy (GPO) and PowerShell Desired State Configuration (DSC)? Why would I use one over the other? I hear these questions frequently. Today we are going to fully explore the pros and cons of each. Is GPO going the way of the floppy disk? Let’s find out.

The Contenders

Group Policy Objects (GPO) have been around since Windows 2000 for configuring Windows clients and servers. They require Active Directory, and domain controllers host the policies. Clients download the policies at login based on their location in the organizational unit (OU) hierarchy and based on filters by security groups and WMI. This is the first choice for managing Windows machines in the enterprise, and it is included in-box with the operating system. GPOs enforce system settings and facilitate compliance with corporate and industry policies.

PowerShell Desired State Configuration (DSC) was introduced with Windows Management Framework (WMF) 4.0. Like group policy, it can configure settings on Windows machines. However, DSC can leverage the automation of PowerShell to configure nearly anything on the system, beyond the preconfigured choices of group policy. DSC is also built into the operating system on Windows 8.1/Windows Server 2012 R2 and above. It is available down level by downloading and installing the latest WMF update (currently 5.1). DSC does not have a graphical management interface and requires knowledge of PowerShell scripting to build out tools for administration.

Group Policy vs. PowerShell DSC

Comparing GPO and DSC is like apples vs. oranges, or pirates vs. ninjas, or Chuck Norris vs. …. Well. They each have strengths and weaknesses. And each technology was created to solve a different problem… in completely different eras of computing. 15 years after GPO we now have DSC, addressing a new set of problems that did not exist when GPO came on the scene.

I like to keep things simple, so let’s make a matrix to compare the two. This comparison will be very thorough. If you are impatient, then skip to the end of the article for guidance on when to use either technology.

If you have ever watched the show Who’s Line Is It Anyway, you know that “everything is made up and the points don’t matter.” I am going to give a point to each product along the categories of comparison. These points are based on my own personal bias, evaluating the capabilities of each technology in the current era computing. Do you disagree? Let me know in the comments area below.

Category GPO Point Point DSC
History I started using Group Policy in 1999 on the released candidate of Active Directory in Windows Server 2000. This familiarity gives GPO an advantage as the incumbent in the room. It also has the advantage of years of feedback and refinement (and acquisitions).
GPO was an evolution of registry.pol files in the pre-Windows 2000 days.
1 DSC began in 2014 with the release of Windows Server 2012 R2, earlier if you count preview releases. Currently it is approximately a “version two” product still gaining momentum with broad community support and feedback. You know what they say, when Microsoft hits version three it is ready for prime time.
Domain Environment and Authentication GPO requires an Active Directory domain for traditional delivery, authentication, permissions, etc. GPO can be delivered to Nano Server via new cmdlets that will import a policy backup, but the policy engine is not available.
Outside of this you can manually configure local GPOs.
1 DSC works in both domain and non-domain environments. In fact, DSC does not even need a network. For one customer I created a thumb drive deployment script for field techs to build servers. It can be that easy. DSC can authenticate via any of the methods supported by WinRM/WsMAN.
DSC now has resources to leverage the Nano Server GPO cmdlets.
Operating System Requirements (including non-Windows) Wow. GPO works out-of-the-box on any Windows machine since Windows 2000. That’s huge.

Scoring this section is difficult. GPO is ubiquitous and easy. DSC is more powerful, more complicated, and not as complete. DSC will win this later with more refinement; for now I’ll call it a draw.

draw draw DSC requires WMF 4.0 or above. (You REALLY want to use 5.x or above.) This is available as far back as Windows 7 and Windows Server 2008 R2. Do you really need to support Windows 2000 any more? If you are still running native PowerShell 2.0 on Windows 7/2008 R2, why? Upgrade today. It’s a no-brainer. The support desk will love you for it.
(The only exceptions here are some server-tier products that don’t take kindly to a WMF upgrade. Be sure to read the release notes prior to deploying across your entire data center.)
You also will need remoting enabled on your machines, which is automatic on Windows Server 2012 and above. If InfoSec doesn’t like this, then send them to this article addressing PowerShell security.
But DSC also supports Linux/Unix machines and network switches… barely. Back in 2014 we announced DSC support cross-platform, but it is a work in progress and not really viable compared to all of the more mature solutions in that space… for now. Keep watching here. Azure is driving this, and it will grow quickly, especially since PowerShell is now open source cross-platform.
Behavior GPO prevents changes to the operating system. When applied to GUI settings, the options are grey and simply unavailable. That is pretty strong.
Group Policy Preferences (GPP) allow greater flexibility of setting something only once or allowing it to be changed temporarily.
draw draw DSC reverts setting via ApplyAndAutoCorrect configuration mode. If something does get changed, then DSC can put it back. However, DSC can also imitate GPO by setting the exact same registry keys and values. This gives DSC the advantage of both prevention and correction.
Like GPP, DSC also has an ApplyOnly mode for initial configuration that can change later.
Authoring Beginning in Windows Server 2003 you could click through the Group Policy Management Console (GPMC) to find and configure settings. Over time the number of settings has grown to thousands, and you need to download a spreadsheet to tell you where to find them in the interface. If you really like GUIs, then GPO is for you. “Just keep clicking; just keep clicking.” 1 DSC is authored in PowerShell, a 10-year-old scripting language that is present in all Microsoft enterprise products. This does require learning new skills, but so does everything else in IT. 15 years ago you had to learn GPO; now you have to learn DSC.
DSC gets the point here, because the power of automation is a force-multiplier when creating configurations.
Move your existing server build scripts into DSC for the win.
Workstation Management GPO wins here, no contest. GPO is your tool of choice for all of the unique workstation configurations across the enterprise. The number of variables would be overwhelming to DSC. 1 Yes, DSC can do workstations. I have a customer using it to apply security baselines across the enterprise, where the settings are all identical. DSC would also be handy for kiosks, classroom computers, and other static configuration scenarios.
Server Management GPO ensures compliance with industry security requirements for companies all around the world. This works well, even for non-domain machines where you have to import security templates. 1 DSC can do all that, too, and even easier than GPO in those non-domain environments.
If you want to manage all of the unique server configurations across the data center, then DSC is going to require more effort and/or paid tools. Stick with GPO and System Center there. DSC would facilitate a good baseline build of each server, though.
Server Build GPO can apply settings and even install software for a new server build, but friends don’t let friends deploy software with GPO. You might have to wait a bit for GPO to fully kick in, even using GPUPDATE. And there is that whole non-domain environment problem as well. 1 This is where DSC shines. It was made for server deployment… over and over and over. On-prem, cloud, you name it. Once the box is provisioned, DSC takes over inside the box to fully build it out. GPO was not intended for this and lacks the broad coverage of PowerShell under the covers. Yes, you could probably force GPO into this, but it would require a lot more duct tape.
Recently I helped a customer deploy non-domain joined Azure scale set VMs with GPO security baselines migrated into DSC. It was a beautiful thing. All servers came up identically and completely secured… all with just a couple PowerShell commands.
DevOps and Cloud Environments The domain requirement encumbers GPO in the agile world of DevOps. In order to deploy the same settings across multiple domain environments you would have to duplicate GPOs in each. This is no trivial task. It also requires management of OU and group memberships outside the DevOps pipeline. 1 If you want to go fast with modern cloud deployments or DevOps Continuous Integration/Continuous Deployment (CI/CD), then DSC is your tool of choice. DSC can make dev / test / qa / prod all match, for real, and keep it that way.
DSC can both build the server and then ensure the configuration going forward. GPO doesn’t have the coverage to compete here.
Extensibility GPO has always had the ability for you to create custom registry setting template files (ADM/ADMX). Advanced GPO customization involves creation of Client Side Extensions (CSE), which requires developer skills. 1 DSC is all about roll-your-own settings, and the customization extends well beyond the registry. You can configure anything that you can script in PowerShell. DSC wins here for ease of customization.
Community Support There may be a few custom items on the TechNet Script Center, but GPO is generally lacking in community extensions when compared with DSC. 1 Um. DSC wins this one hands down. From the beginning Microsoft has encouraged community contributions, and we have a rich GitHub and Gallery environment full of community content. This is one of the first times in history YOU have been able to work WITH Microsoft on the product. Our DSC resources are all open source and welcoming of your improvements and fixes. Of course the community is full of other code repositories as well.
Third Party Support GPO has a few vendors who have improved the functionality of the product over the years, and Microsoft acquired some of those to put in the box (ex. Group Policy Preferences, AGPM – Advanced Group Policy Management). The group policy MVPs Jeremy Moskowitz and Darren Mar Elia each have released a number of GPO enhancements as well. draw draw Where DSC lacks in robust management features, third party vendors have stepped up. Chef and Puppet lend their enterprise readiness from the Linux side of the house to make DSC more administrator-friendly at scale.
Also, Azure Automation DSC has a nice dashboard experience for managing configurations and nodes. Keep an eye on this space.
Delivery Method Group Policy uses a pull model. The client logs on to an Active Directory domain. Then it begins a back-and-forth conversation to discover all the policies and download their respective files. “Got any jacks?” “Go fish”
The advantage of Active Directory is that the Domain Controllers (ie pull servers) are highly available and replicate automatically.
1 DSC offers push and pull. Similar to GPO, DSC can download a setting template (MOF) and the files that make it happen (resources). This pull server can be set up for SMB, HTTP, or HTTPS transport. However, the in-box pull server feature is not highly available. The Azure DSC pull server is highly available for nodes both on-prem and in the cloud, but this requires additional cost.
DSC additionally has robust support for peer-to-peer delivery of settings via push.
Firewall GPO uses an assortment of ports: SMB 445, RPCSS 135, RPC random ports 1 One port, encrypted by default. WinRM/WsMan 5985, optionally SMB only if the configuration leverages it.
Scalability Both GPO and DSC scale to thousands of machines. GPO wins for ease-of-use here. 1 DSC requires your own tooling and automation to scale. It is honestly much more work than linking a GPO to an OU. However, the automation and complexity of DSC makes it much more powerful than GPO.
If you need to encrypt credentials in DSC configurations, then scalability gets much more complicated with certificate management. It can be automated, but it is more complex.
How many can I have? It is really easy to apply multiple GPOs to a single machine, and you can see the result using GPRESULT or RSOP. You might have to trace down conflicts, but there is a clear winner and clear rules. 1 DSC can use partial configurations to apply multiple, unique MOF files to a single system. However, this is not best practice. Worse, this is a tedious process of configuring the LCM with specific names and publishing those via push or pull. GPO wins here for ease-of-use.
Raw Power GPO owns the Windows registry and obscure security settings that are difficult to reach via scripting techniques. It is a solid work-horse in this area. And Group Policy Preferences extend configuration coverage considerably. However, it simply lacks the breadth of settings compared to DSC, especially when we factor in ease of user-extensibility. 1 DSC can do just about anything GPO can do, but it has the impressive force of PowerShell behind it. Anything you can do in PowerShell can be deployed to all your nodes. The logic and extensibility of scripting is a clear winner here.
Timers GPO applies every 90 minutes, plus or minus up to 30 minutes, on machines in the domain. The exception is domain controllers which apply GPO every 5 minutes.
This interval is configurable in the registry from 0 minutes to 45 days, but this is not a common practice.
We will give the point to GPO here for the smallest refresh interval, but setting a smaller timer with either technology can cause issues.
1 DSC has two timers: 1. ConfigurationModeFrequencyMins determines how often the box is scanned for configuration drift. The minimum value is 15 minutes. 2. RefreshFrequencyMins is how often it polls the pull server for a new configuration to apply. This minimum is also 15 minutes.
These values must be a multiple of one another.
Whatever you do, don’t put the same setting in both GPO and DSC. The timers will battle back and forth resetting the same value all day long. There is no automatic conflict detection between the two.
Command Line GPRESULT and GPUPDATE are the most common commands. GPO also has a PowerShell module full of helpful commands like Invoke-GPUpdate and Get-GPResultantSetOfPolicy. The module is available when you install GPMC. However, GPO loses a point here, because the PowerShell cmdlets only work with registry-based settings of policies and preferences. When you try to script individual GPO settings you will hit this wall pretty fast.
To be fair, there is a decent set of cmdlets for working with whole policies (links, inheritance, backups, permissions, etc.).
1 DSC has a vast array of command line support, since it was borne out of PowerShell:
Get-DscConfiguration
Get-DscConfigurationStatus
Get-DscLocalConfigurationManager
Remove-DscConfigurationDocument
Restore-DscConfiguration
Stop-DscConfiguration
Invoke-DscResource
Publish-DscConfiguration
Set-DscLocalConfigurationManager
Start-DscConfiguration
Test-DscConfiguration
Update-DscConfiguration
Logging Both GPO and DSC have their own Windows Event Logs. 1 I am going to give the point here to DSC, because of the xDscDiagnostics module that does some cool collation across all the log sources. Also, DSC has a second logging mechanism to view with Get-DscConfigurationStatus, and this data is available centrally in Azure Automation DSC or from the in-box reporting/pull server.
Troubleshooting GPO has a generous assortment of event logs, text log files, and command line utilities for troubleshooting.
GPO cannot do the live debug like DSC, at least in a user-friendly way. Well, I suppose you could attach a Windows debugger to troubleshoot GPO. Do you know anyone who can do that (besides people at Microsoft)?
1 DSC has the dominance in command line and logging as discussed above, but it also has the ability to live debug remotely with no special tools as a configuration is applying. Now that’s cool!
Version Control Version control and release scheduling for GPO requires an additional license for Advanced Group Policy Management (AGPM). 1 Since DSC is configuration-as-code, any source code management tool will work. Popular options are Visual Studio Team Foundation Server (TFS), git-based solutions, and other third party products. I’ll give the point to DSC here, because some of these are free.
Updates GPO combined with WSUS is an effective patching solution for many organizations. This is an established pattern that works well. “If it ain’t broke, don’t fix it.” 1 Yes, DSC can apply patches or updates using the xHotfix resource. However, you really don’t want to write all of that in configuration-as-code. Even though you could automate it with scripting, it is less than ideal. Stick with your other patching solution.
The only exception here would be doing a new server build. Sometimes there are certain patches you might want to lay down first before proceeding to configure the box (like WMF 5.1). One-off patch scenarios like this are well-suited to DSC.
What-If Scenarios GPO can use RSOP modeling to determine “what configuration would this user and computer combination get in these OUs?” 1 DSC has a similar feature using
Test-DscConfiguration
-ReferenceConfiguration. The advantage goes to DSC for the ability to scan multiple machines simultaneously and return object-oriented data for easy bulk reporting.
Reporting How would you produce a list of machines that were in or out of compliance with GPO? There is RSOP and GPRESULT, but those are quite tedious to view the entire environment. Perhaps you have a third party product to do this, but this visibility across the enterprise is not easy for GPO. I guess you could use the RSOP cmdlets if you wanted to build your own solution. 1 Enterprise-wide compliance reporting for DSC is marginally better. The current in-box reporting server leaves a lot to be desired (like high availability), and the Azure Automation DSC solution costs money. However, you can script your own reporting solution using a number of DSC cmdlets like Test-DscConfiguration, Get-DscConfigurationStatus, etc.
I have heard of one person who built their own SCOM management pack for DSC. Other customer may leverage a System Center script to collect and report this data.
DSC has a nice object model to clearly identify which parts of the configuration are in and out of desired state.
Long-term Microsoft Direction Many people wonder if “GPO is dead”, but we are still releasing new policies for Office and Windows with each subsequent version. I do not expect this to go away any time soon. 1 Microsoft is making significant investments in DSC and it is used widely across our modern offerings. This is not a passing fad. Learn it now. It will be here for decades to come. GPO, only time will tell. The PowerShell DSC team at Microsoft is full of ex-Group Policy product people. Maybe that is a clue.
Point Tally Group Policy 7 16 PowerShell DSC

 

Summary Recommendations

Look at the score! Do these points really matter? Maybe. Depends on your goals. Clearly I am biased towards DSC. Why? Growth mindset. Stay locked into the old ways of GPO, or learn the new ways of DSC. Your choice. Tell me what you think in the comments area below.

At the time of this writing each technology has its own pros and cons. Here are the scenarios where I see each as most useful:

Group Policy PowerShell DSC
  • Enterprise workstations
  • Complex scenarios requiring deep layering or filtering of settings
  • Patching with WSUS
  • Staff with only GUI skills
  • Server builds and baseline configurations
  • Static workstations
  • DevOps
  • Cloud and nano server deployments
  • Non-domain environments
  • Configuration drift scenarios
  • Compliance reporting

If you are the typical enterprise environment, don’t rip and replace GPO with DSC. If you are building green field, doing DevOps, or moving to the cloud, then start using DSC right away. I recommend standard DevOps advice in every case: start small with DSC in a limited scope, learn it, get some early wins, and then build out the span of control as your experience and the product grow.

If you still have not learned PowerShell, then you are at a severe disadvantage in your career. PowerShell is not a “new thing”; it is 10 years old. Similarly, Desired State Configuration is three years old now. This is not one of those “wait and see” technologies. It is here to stay. Learn it today.

Resources

There are several places to learn about PowerShell Desired State Configuration online:

  • Start here: https://microsoft.com/powershell. This page includes links for documentation, WMF download, etc. The documentation includes many code samples for getting started.
  • Microsoft Virtual Academy has several good videos for training on DSC.
  • Channel 9 also has many good training videos.
  • Follow #psdsc on Twitter for all the latest news and blog posts. Connect real-time with people using DSC in the real world.

Practical PowerShell Security: Enable Auditing and Logging with DSC

$
0
0

Windows_Insiders_Ninjacat-100PowerShell Security

Almost two years ago Lee Holmes released his famous PowerShell ♥ the Blue Team whitepaper. This is required reading for anyone who works with PowerShell at all in their job or who is concerned about the security of PowerShell in their environment. I outlined a number of PowerShell security-related resources in this previous post: http://aka.ms/pssec.

I am not going to rehash all of the topics in the white paper, but I do want to make it easy for people to implement PowerShell auditing and logging. What better way than putting Lee’s recommendation and code samples into a Desired State Configuration (DSC)? If you would like to see Lee demonstrate these improvements you can watch the third module of this video series: http://aka.ms/MVAps5.

Practical DSC

Sometimes customers ask me what should go into their baseline configurations for servers. Now that is a fun conversation. Let’s just say PowerShell auditing is an easy one to overlook. PowerShell security is not on the radar in many IT shops. With this DSC configuration sample below it can become routine.

Security Features

As Lee outlined in the whitepaper, WMF 5.x includes a number of enhancements in the area of security:

  • Script block logging
  • System-wide transcription
  • Protected event logging (used together with Windows Event Forwarding)
  • and more…

Lee even provided sample code to set the Group Policy registry values to enable these enhancements. In DSC it is really easy to set registry values, so let’s get to it.

Requirements

We are assuming that the target system already has WMF 5.x installed or upgraded. Each of these enhancement will require the following settings:

  • Script block logging
    • HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging
      • EnableScriptBlockLogging, 1
      • EnableScriptBlockInvocationLogging, 1
    • It may also be a good idea to increase the log size. The Microsoft-Windows-PowerShell/Operational log is 15MB by default.
  • System-wide transcription
    • Create a directory to hold transcripts
      • Set permissions on the directory to prevent tampering. (I chose SDDL for the shortest code here.)
      • Trim the transcript directory contents on an interval to avoid filling the drive (if local).
      • We are going to use a local directory for now. Lee recommends pointing it to a share off-box.
    • HKLM:\Software\Policies\Microsoft\Windows\PowerShell\Transcription
      • EnableTranscripting, 1
      • IncludeInvocationHeader,1
      • OutputDirectory, [Path]
  • Protected event logging (can be used together with Windows Event Forwarding)
    • Requires Windows 10 or Windows Server 2016
    • Requires a document encryption certificate
    • HKLM:\Software\Policies\Microsoft\Windows\EventLog\ProtectedEventLogging
      • EnableProtectedEventLogging, 1
      • EncryptionCertificate, [Certificate]

Note that the logging and transcription enhancements include an option for invocation logging. This is optional and will increasing the logging volume. It basically adds start/stop header information for each command that is executed. You can omit this setting if you prefer a lower logging leverl.

Desired State Configuration

Now that we have an outline of the settings required, we can move those into a DSC configuration. You can view the code on my GitHub account here.

  • Script Block Logging
    • Two registry resources set the values.
    • Then for good measure we use a script resource to increase the size of the PowerShell event log.
  • Transcription
    • Three registry resources set the values.
    • We need a file resource to create the directory to hold the transcript files.
    • Then two script resources set the permissions on the directory and remove any old files. We probably could have used an external resource to set the directory permissions, but I want to keep this using in-box resources for simplicity. Keeping the transcript directory clean requires that you set the DSC Local Configuration Manager (LCM) to ApplyAndAutocorrect.
    • NOTE: Remove the file and script resources if you send the transcripts to a remote UNC share path.
    • NOTE: If you use a local path, have fun trying to read the transcript files. Also, the trim files script resource will likely generate warnings trying to clear old files.
  • Protected Event Logging
    • I’m going to skip this one due to a couple reasons:
    • Right now we do not have a way to request a certificate in a configuration, and then pass that data to another resource in the same configuration. Writing a custom resource for that wouldn’t be practical, because I’m trying to keep this to in-box DSC resources for now.
    • Most customers already have an event collection tool (SIEM). If not, then explore the xWindowsEventForwarding resource module.
  • Fit and Finish
    • Notice that the configuration has the following parameters:
    • TranscriptPath – Directory where you want to put the transcript files. Can be local or UNC path.
    • TranscriptDays – How many days of transcripts do you wish to retain?
    • EventLogSizeInMB – Size to set for the PowerShell log to hold the additional content generated.
  • BONUS
    • For completeness I threw in a configuration to disable the transcription and logging.
    • I also threw in a couple lines to query the event logs for your new events.

Ideally you would take this sample code and create two configurations: one for the nodes being audited and one to set up the server with the UNC share receiving the transcripts and Windows Event Forwarding.

The code on my GitHub account is purely sample for you to copy/paste into your own configurations. This makes a great finish for a baseline server security config.

Gotchas

The PowerShell console and ISE will cache group policy settings when they are launched. In order to see the effects of the logging and transcription you will need to open a new session.

If you have DSC set to scan the node for compliance (as most of us do), note that this will generate a significant amount of logging via each of these methods.

So if you decide to put the transcript folder on the local box, then the DSC configuration is going to error out when it goes to check the folder for old files to purge. You will see orange warning text when this happens.

Audit Thy Servers

Now you have a cool whitepaper on PowerShell security to read and some free DSC code to play with. Use the comments area below to discuss any questions or ideas.

Cheers!

Viewing all 28 articles
Browse latest View live