Category Archives: Uncategorized

ACLs Folder class

‘Sup PSHomies,

I recently had to make a quick Backup & Restore of ACLs three levels deep. Nothing fancy, just two functions, but that got me thinking…

Why not make a class of this?

And so I did! Here’s the framework for the class:

classACLFolders

Here’s a list of the methods:

  • Backup. Backup SDDL from the property $Folder of the class
  • Restore. Restore SDDL to the property $Folder of the class
  • Clone. Clone will take a target Folder and clone the SDDL of $Folder to it
  • ConvertSDDLToAccess. This will enumerate what the SDDL stands for

Default Constructor

classACLDefConstructor

The default constructor will evaluate the folder used to instantiate the object. If successful, the SDDL, Owner and Access is retrieved using  the Backup() method. All actions are registered for future reference.

Instantiating is pretty straightforward:

instantiateClass

Backup()

classACLBackup

This will retrieve the SDDL for the folder and enumerate the Access.

Restore()

classACLRestore

Restore is a bit tricky. For one you need to make sure it isn’t empty. Set-Acl has no problem setting an empty SDDL, blowing everything open (worst case scenario, and that’s why you should test this in a lab first!). The other challenge is having a valid SDDL string. You can change the SDDL string if you want to something gibberish, hence the typecast as a precaution.

Clone()

classACLDefClone

The same goes for cloning. In this case we need to test the target path. Alternatively, you could  also change the Folder to a new path… It works, you’d just have misleading ActionHistory entries… I wonder if there’s a way to make this read-only,  just thinking out loud here… (note to self)

ConvertSDDLToAccess()

This is just a lil’ something extra. Like I said in a previous blog SDDL really gives more information. For one, the SID will let you know which domain this object belongs to. One thing I ran into with ReACL is that SIDHistory will resolve to the current NTAccount. This had me puzzled for a while until I saw that the SIDs in SDDL where different.

Here’s what the ouput looks like:

convertSDDLToAccess

Now for those of you that are wondering just what is this AccessMask, wonder no more! 🙂

Remember the RoboCopy ExitCodes blog I did a while back? Well it’s the same principal 🙂 This is why classes & everything related should be on your radar…

enumAccessmask

Here’s how this works…

Say I wanted to evaluate the AccessMask of a SDDL entry

AccessMaskEnum

Here I have the SID & the NTAccount. This is the builtin administrators account but it also works for Domain accounts.classACLConvertSDDLToAccess

There’s a private function that will translate the SID accordingly.

To see what the account can actually do we can enumerate the AccessMask

AccessMaskEnum1

This is what we’d see using the advanced Security GUI tab of a folder.AdvancedPermissions

Not bad… Not bad at all…

I can’t state this enough, SDDL is NOT to be be trifled with. Yes you need admin rights and please try this is a testlab first.  SDDL is very potent, if used with caution, it could do a whole bit of good!

So finally, here’s the code…

Hope it’s worth something to you…

Ttyl,

Urv

Advertisements

AD Security Group matrix

‘Sup PSHomies,

So last blog was about adding members to a security group efficiently. Which got me thinking, can I reverse this process? If given the security groups with specified members, can I recreate the csv? I do love me a challenge!

So to pick up where we left off, I’ll be using the $addADGroupMembers to repopulate the csv…

#Security Matrix
$Groups = $addADGroupMembers.Keys
function Convert-ArrayToHash($a){
    begin { $hash = @{} }
    process { $hash[$_] = $null }
    end { return $hash }
}

$template = [PSCustomObject]([Ordered]@{UserID=$null} + $($Groups | Convert-ArrayToHash))

$addADGroupMembers has all the group names we need. I’m converting the group names into an empty hashtable. The $template variable is a custom object I’ll be using to move things  along, I’ll explain as we go…

matrix-template

Now for the tricky part…

$arrMatrix = @()

$Groups |
ForEach-Object{
   $GroupName = $_
   if($addADGroupMembers.$_){
      $addADGroupMembers.$_ |
      ForEach-Object{
         if($arrMatrix.Count -eq 0) {
            $newItem = $template.PSObject.Copy()
            $newItem.UserID = $_
            $newItem.$GroupName = '1'
            $arrMatrix += $newItem
         }
         else{
            if($arrMatrix.UserID.contains($($_))){
               $index = [array]::IndexOf($arrMatrix.UserID, $_)
               $arrMatrix[$index].$GroupName = '1'
            }
            else{
               $newItem = $template.PSObject.Copy()
               $newItem.UserID = $_
               $newItem.$GroupName = '1'
               $arrMatrix += $newItem
            }
         }
      }
   }
}

First we have an array to save the results. We only need to worry about groups with members. The $template has been initialized with $null. The first time it runs, $arrMatrix.Count will be zero, so just add this group to get things started. Here’s where it gets interesting, in order to add a newItem to the array I have to clone it first. Adding and saving this way makes sure I have a row with a unique UserID. Truth be told I had to google to figure this one out. Modifying $template and then assigning it to $newItem will only assign the reference. Change the value once more and every item in the array changes! I read it somewhere, it was fun to stumble on this… The more you know…

The next trick was to find the index of a UserID already saved. Google to the rescue! I found this neat trick of using [array]::IndexOf(). This will give you the first index with that value. Lucky for me, my UserIDs are unique 😉
Once I have my index I can add a value of ‘1’ to the group if the UserID is a member. If I can’t find a UserID then a new unique UserID is added to the $arrMatrix

Ok enough chit-chat here’s some code to play with

This should be your endresult

securitymatrixresults

No too shabby eh? 😛

Ok Urv that’s all good and well but when am I going to use this?

Why thank you for asking!

If you’ve ever been in charge of implementing Role Based Access Control then you could appreciate this. A security matrix like this is where I’d start, only now you don’t have to start from scratch… 😉

Here’s how it works…

adsecuritymatrix

I created a security group Rol-Consultant for RBAC purposes. This group is a member of all the APP-* groups giving any member access by way of group nesting. Users who are a member of Rol-Consultant don’t have to be a direct member for access. The down side of RBAC is it’s all or nothing, exceptions are real deal breakers…

I did a blog about reporting a user’s nested group membership. Let take user ‘dlbouchlaghmi’. This is what his effective user group membership looks like in list form

nestusergroupmembership

The security matrix makes it a bit more visual. Granted, it takes some getting use to but the information is there. Now you can ‘fix’ any issues and reapply the way you see fit! 😉

This has been on my radar for quite some time. Processing security groups this way, makes scripting, I wouldn’t say easier, but more easier to manipulate if you catch my drift…

Ok here’s the code to get the ADSecuirtyMatrix. Do be careful with groups with large memberships. I tried my hand at a group with more than 3800 member, took a couple of minutes, but it worked.

I got one more use to go… Some Operation validation! Stay tuned…

Hope it’s worth something to you…

Ttyl,

Urv

Get DSA object creation date

‘Sup PSHomies,

The project manager is on to me! 😛

PM: “PowerShell is awesome!!!”

Me: “You know it!!!”

PM: “Glad you agree! So here’s what I need, We need a weekly update of all users, groups in the source domain based on their creation date…”

Me: “Wait, what just happened?

PM: “You were agreeing that PowerShell is awesome? (Grinning)”

Me: “Well played… I ain’t even mad mad at ya…”

And so begins another PowerShell journey 🙂

The idea here is to be proactive in our migration. Instead of asking for a list of newly created users/groups we’ll gather the information ourselves. All the customer has to do now is validate our list as to who is relevant. Which got me thinking, why stop at user/groups?

Remember I needed to recreate the DFS Structure? The data that I used was from February. What if there were newly created DFS links in the mean time? Turns out my hunch paid off!

Now curiosity got the better of me… “What about accounts that were deleted?” We’re migrating in batches. My first action is always to verify that the accounts in the batch exist. Having a list of deleted objects helps verifying it wasn’t a typo and that this object isn’t relevant anymore…

Here’s what I came up with:

I added Contact and PrintQueues as a bonus 😉

For reporting it’s ImportExcel to the rescue!

dsaobjects

At first I added a extra property in order to lookup the creation date using yyyyMMdd date format. Turns out it wasn’t necessary. You can just a easily use a filter on Created

dsaobjects-filter

The PM is quite pleased… PowerShell is Awesome!!! But you already knew that… 😉

Hope it’s worth something to you

Ttyl,

Urv

 

DFSn links Operational readiness

‘Sup PSHomies,

So here is the follow up on the previous blog.

I recreated the shares, check! Now it’s time to create the DFSn Links & targets!

Here’s the code to create the necessary links and targets:

Quick run down. The csv is straight forward Link, Target (tab delimited). I created a few checkpoints (again, better safe than sorry).First, I get a list of all actual DFS links & targets for reference. If the target doesn’t exist create it. That’s where the SMB share preparation came in 😉 If the link doesn’t exist create it. If the target exist, verify that it’s set to the specified link.

In my case I only have 1:1 Dfs link/target relationships. So this worked for me. Be sure to test this before trying it out in production.

I needed to recreate 1386 DFS links. This took a few minutes. 10 failed, not bad considering the amount. Now the old Irwin would have panicked at the sight of something going wrong (Whooosahhh). I kept it together and let script ride out. Once it was done I did my OVF to see which ones  failed 😉

This is one of those rare instances that I created the missing links by hand (don’t judge me I was on a tight schedule). Turns out a few had some form of a special character in the name. Creating them by hand didn’t raise an issue.

Last but not least I wanted to generate a ReportUnit HTML of the DFSn test results. Generating the ReportUnit HTML file didn’t go as I expected. It did succeed in the end., but generating a HTML report for 2772 was a bit too much. Having said that…

There’s a module for Formatting Pester result using PScribo created by Erwan Quélin. Definitely check it out if you want to do everything in PowerShell (Who doesn’t? :-P)

Usage is pretty easy:

dfsformatpesterps1

Here’s a quick screenshot of Format-Pester output:

dfsformatpester

Nice!

Once I resolved the failed test, I ran the test again, nothing but purple and green!

A quick notification in Slack using PSSlack by @pscookiemonster (Even though I’m the only one using Slack at the moment, give it time…)

Awesome!

So I learned that the size of the test when using ReportUnit.exe could be an issue, but if you want to do everything in PowerShell then Format-Pester is a better fit.

Hope it’s worth something to you

Ttyl,

Urv

File servers configuration report

Sup’ PSHomies,

I recently blogged about how awesome PScribo is, couldn’t forget my other favorite go to module when it comes to reporting: ImportExcel brought to us by Doug Finke!

I’ve blogged about my love for csv files and what the possibilities are when it comes to exporting and what to look out for.

My reason for exporting to csv is mostly to create Excel reports. Well if that’s your case you might as well just cut out the middle-man and go straight to the source!

Excel is a great way to analyze your data. I know my way around Excel so that helps.

The title of this blog is about file servers configuration. Think volumes, shares etc etc. The idea is to gather all File server related data (Now where have you seen that before 😛 ) and create a xlsx file report.

I don’t know about you but it seems like the community is producing more and more high quality blogs on just about every subject you can think of! I can barely keep up!

I enjoyed Jaap Brasser’s take on storing your credentials. Thanks for sharing Jaap! 😉

I’m using a scriptblock in combination with invoke-command to gather the needed information . The scriptblock returns a custom object.

$sbStorage = {
    [PSCustomObject]@{
        Volume = $(Get-Volume | Select-Object *)
        SMBShare = $(Get-SmbShare | Select-Object *)
        SMBShareAccess = $(Get-SmbShare | Get-SmbShareAccess)
        SMBShareNTFS = $(Get-SmbShare |
            Where-Object{ $_.Name -ne 'IPC$'} |
            Get-Acl |
                Select-Object @{Name='Path';Expression={($_.Path).Replace('Microsoft.PowerShell.Core\FileSystem::','')}},
                Owner,Access
        )
        Disk = $(Get-Disk | Select-Object *)
        VSSShadows = $(vssadmin.exe list Shadows)
        VSSWriters = $(vssadmin.exe list Writers)
    }
}

#region Main
$snapshotStorage = $Servers |
ForEach-Object{
  Invoke-Command  -ComputerName $_.ComputerName -ScriptBlock $sbStorage -Credential $cred
}
#endregion

I’m using admin credentials in my test lab so this will also work without -Credential. This was sufficient in my case.

Here’s a quick rundown on what the script basically does. Let’s take a look at documenting Shares to get the general idea…

#region Get Shares
$snapshotStorage |
ForEach-Object{
    $ComputerName = $_.PSComputerName

    $_.SMBShare |
    ForEach-Object{
        [PSCustomObject]@{
            ComputerName = $ComputerName
            Name = $_.Name
            Path = $_.Path
            Description = $_.Description
            ShareState = $_.ShareState
        }
    }
}|
Export-Csv .\export\storage\FS_SMBShares-$($exportDate).csv -Encoding UTF8 -Delimiter "`t" -NoTypeInformation

#Export to xlsx file
Import-Csv .\export\storage\FS_SMBShares-$($exportDate).csv -Encoding UTF8 -Delimiter "`t" |
Export-Excel -Path $xlsxFile -WorkSheetname SMBShares -AutoSize -BoldTopRow -FreezeTopRow
#endregion

For each server we’ve captured share information to $_.SMBShares. Simply select the properties you want and save to a custom object. Saving to csv and then exporting to Excel makes sure that everything is a string . This is one of those times that having your object cast as string comes in handy ;-). Also, most of us don’t have Excel on every server. Having the csv files let’s you quickly assess what you can expect in your Excel report.

Export-Excel has quite an extensive parameterset

Export-Excel syntax

No need to open the xlsx file, autosize and freeze to the toprow, just add the following switches -AutoSize -BoldTopRow -FreezeTopRow and your good to go!

Here’s a quick impression of the xlsx file

File Server Excel Report

I can’t say enough good things about Import-Excel. Doug Finke actively maintains this module and is open to suggestions to make it better! Thanks for making reporting in Excel so much easier Doug!

Hope it’s worth something to you

Ttyl,

Urv

Active Directory Operations Test

‘Sup PSHomies,

Last blog I demonstrated how to create a HTML report from the Active Directory configuration snapshot. Here’s yet another way to get more use out of the Active Directory configuration snapshot.

I started out with the intention of reporting, then it hit me, why not use the snapshot for Operation readiness? Let’s dive in, I’ll explain as we go along…

Before we get started, you’ll need to have your Active Directory specification at hand. Modify $ADConfiguration according to your specifications.

#region Active Directory configuration as you expect it to be. Modify to reflect your Active Directory
$ADConfiguration = @{
    Forest = @{
        FQDN = 'pshirwin.local'
        ForestMode = 'Windows2012R2Forest'
        GlobalCatalogs = @(
            'DC-DSC-01.pshirwin.local'
        )
        SchemaMaster = 'DC-DSC-01.pshirwin.local'
        DomainNamingMaster = 'DC-DSC-01.pshirwin.local'

    }
    Domain = @{
        NetBIOSName = 'PSHIRWIN'
        DomainMode = 'Windows2012R2Domain'
        RIDMaster = 'DC-DSC-01.pshirwin.local'
        PDCEmulator = 'DC-DSC-01.pshirwin.local'
        InfrastructureMaster = 'DC-DSC-01.pshirwin.local'
        DistinguishedName = 'DC=pshirwin,DC=local'
        DNSRoot = 'pshirwin.local'
        DomainControllers = @(
            'DC-DSC-01'
        )
    }
    PasswordPolicy = @{
        PasswordHistoryCount = 24
        LockoutThreshold = 0
        LockoutDuration = '00:30:00'
        LockoutObservationWindow = '00:30:00'
        MaxPasswordAge = '42.00:00:00'
        MinPasswordAge = '1.00:00:00'
        MinPasswordLength = 8
        ComplexityEnabled = $true
    }
    Sites = @('Default-First-Site-Name')
    SiteLinks = @(
       @{
            Name = 'DEFAULTIPSITELINK'
            Cost = 100
            ReplicationFrequencyInMinutes = 180
        }
    )
    SubNets = @()
}
#endregion

Quick sidestep, we’re in the middle of implementing a new Infrastructure for a customer. Some post configuration had to be done, FSMO roles rearranged, Global catalogs etc. etc., you know the drill. I got my hand on the Active Directory specifications and filled it in. I did a AD configuration snapshot and was now ready to compare. My colleagues were in the middle of post configuring Active Directory. I noticed that the FSMO roles weren’t as expected. I was missing a Domain Controller and some Sites, subnets and sitelinks. I did a AD snapshot the next day, ran my operation readiness test and surprise, everything was as expected! It wasn’t my intention to supervise my colleagues, but I could give them the good news that the Active Directory is configured as specified.

To give you an idea of what to expect, I did the operation readiness test on my lab. Here’s the script:

And here’s the result:
AD Operation Readiness
My testlab is quite simple.

Validating operation readiness will definitely help you keep things in check! No second guessing: “Did I configure server x as a Global catalog? With the AD Configuration snapshot you can be certain how you left things! “I know for a fact I configured the server as a Global catalog last week.” Compare your past snapshot to what you’re expecting. Create a new snaphot and compare again. If it’s different… Well… Sometimes colleagues forget to communicate changes that have been made… At least you don’t have to second guess yourself 😉 As an OPS guys Operation readiness has my vote!

Hope it’s worth something to you

Ttyl,

Urv

Coding for speed

The results are in! Great summary about the Hadoop PowerShell Challenge by Stephen Owen! It was fun to see the different approaches. When it comes to speed you can’t beat native C# code! Great tips! Worth the read!

FoxDeploy.com

I must say that I learned a lot about speed, and how coding structure matters when you’re going for the gold, as I was reviewing the entries from the Hadoop PowerShell challenge. The winners are at the end of this post, so zip down there to see if you won!

I’ll use the post to cover some of what we learned from the entries here!  Here’s our top three tips for making your PowerShell scripts run just that much faster!

When searching through files, don’t use Get Content

As it turns out Select-String (PowerShell’s text searching cmdlet) is capable of mounting a file in memory, no need to gc it first. It’s also MUCH slimmer in memory, and has speed for days.  Look at the performance difference in a common scenario, search 10 directories of files with it, and with Get-Content.

Using Select-String alone is a 31x Speed Increase!  

View original post 1,421 more words