Monday, 5 July 2021

Update custom attributes with replace option in powershell

Little Background:- 
   
    There was request from client to segregate the different types of account exists in the customer internal domain. It may be difficult if those accounts are not defined already with their type of usage for example : Daily user normal account, Administrative account, Workstation Administrator and Shared accounts. 

    So, we decided clean-up and setup procedure to update the "EmployeeType" attribute for all the users.. 

    As a initial step, we have exported all the enabled accounts and add new column named Employeetype. 
By naming convention, we could different account types and update the new column. 


Once it's completed, we prepare the Input file with header "Username" & AccountType"









Before processing, I take note of the existing employeetype for given user in input file. 

Sample cmdlet for easy reference: 

 Import-csv .\Userslist.csv | Foreach-object {Get-Aduser -Identity $_.Username -property Employeetype | select Name,Samaccountname,employeetype}




After executing the script :- 









# *****************Start of Script ********************

# Make sure that input CSV file have header like Username, AccountType
#Preparing the parameter input file

Param (
[Parameter(Mandatory=$True)]
[string]$InputFile
)


# Preparing the Log file naming format ( Default stored in same place where script is executed )

$logdate = (Get-Date -Format yyyyMMdd-hh-mm)
$log= $logdate+"_EmployeeType_Update"+".log"

# Importing Active Directory Module & Getting Logged on Domain Name information

Import-Module ActiveDirectory

# Looping through the each line of user from the Input file

ForEach ($Eachline in (Import-csv $InputFile)){

    $Sam = $Eachline.Username
    $Acctype = $Eachline.AccountType
  

  $ADUser = Get-ADUser -Filter {SamAccountName -eq $sam}
 
if ( $ADuser -ne $null )

{
  
  Set-aduser $ADUser -replace @{Employeetype="$Acctype"} -Verbose
  
  $Info= "EmployeeType field updated for $ADUser.Samaccountname"
  $Info | out-file -Append $log
  
}
else

{
$info="$Sam ID not found in Domain. Please recheck"
$info | out-file -Append $log
}

}

# *****************END of Script ********************

Local Administrator Group Membership Listing for multiple servers

Little Background:

Hello , 

It's kind of already weekend started... :) but suddenly remembered that I missed to post the items which I worked on earlier. So, here is the request that I received as part of my work. 

         I was assigned a project to do the clean-up of local administrator group membership to be restricted through GPO. So, here is the tasks that we plan to do .

                     1) Who all are in the current local administrator group membership

                    2)  What is the strategy that need to be followed to move the locally assigned principals  to domain group

                    3) How to assign the domain group to the Local administrator group on each server ? 

 We mainly discuss about the line item 1, in this post ... please skip the mind from the other items listed above for now, I will try to cover them in my next blog, probably during another pleasant weekend ;)


 Main Topic:-

How to generate a report of local administrator group membership of listed computers  ?

I know there are plenty of scripts already available in the internet for this task, but why did I build this script ???
               It's because, just for learning the POWERSHELL SCRIPTING. I understood one point is that unless you start working with POWERSHELL SCRIPTING in real-time scenarios, you won't get chance to work at no time. So, utilize whenever, we get chance.

Script Logic used:- 

                 1) Use the ADSI method to get the information about the group membership
                 2) The output is not formatted like we wanted, so here is where the splitting, Joining works starts
                 3) I have added the Test-connection method , just to validate that computer is reachable or not.
                4) Included the logging for each processing, so that we can cross check if something not correct.
                5) Always, I stick to rules of working with input file method as much as needed. This is just to avoid any BIG mistake during the testing / Production and it will give possibility to touch only listed items. 

Script Content :- 

Copy from below starting "# " to the end

# Script  to pull the Local administrator group list from the remote computers
# Input file should contain the server / workstation names one on each line.
# Example: .\Ladmin_Listing_Latest.ps1 -inputfile ".\serversList.txt"
# Make sure that you have the serverslist.txt file exist in the same folder where the script exist, otherwise, you need to provide
# the full path of the input file.
# Author : Murugan Natarajan
# Email  : murugan.natarajan@outlook.com
# Script created date: 7/5/3/2021
# Disclaimer: Script provided as is without any warranty, please use it with your own risk.


param(
[Parameter(Mandatory=$True)]
[String]$Inputfile='.\ServersList.txt'
)

$logdate = (Get-Date -Format ddMMyyyy-hh-mm)
$FinalLog= ".\$($logdate)_LocalAdmin_List.csv"

Foreach ( $SName in (Get-Content $inputfile) ) {

        $Message= " " # Adding empty line for each item processing
        $Message | Out-File $FinalLog -Append
       
        If (Test-Connection $SName -Count 1 -Quiet -ErrorAction SilentlyContinue) {


$group = [ADSI]("WinNT://$SName/Administrators,group") 
$GMembers = $group.psbase.invoke("Members")
$Liste=$GMembers | ForEach-Object {$_.GetType().InvokeMember("ADspath",'GetProperty', $null, $_, $null) -replace ('WinNT://DOMAIN/' + $Sname + '/'), '' -replace ('WinNT://DOMAIN/', 'DOMAIN\') -replace ('WinNT://', '') }# | Out-File $FinalLog -append

#

foreach ( $object in $Liste ){

$Message="$sname,$object"
$message | Out-File $FinalLog -Append

}
}
    else{

        $Message="$SName,Problematic server"
        $message | Out-File $FinalLog -Append
    }

}

#   Script line ends here

Important note: Please make sure that you specify the input file before executing the script, it won't harm, instead it will prompt to provide the full path for the input file because the parameter is made as mandatory.


Tail note: Hello everyone, I have written this blog on my experience, if you find any mistake, please leave comment. I will correct it.

Next topics to cover:- 

   2) GPO method to restrict the Local administrator group membership
   3)  Automate the basic groups needed for this scenario.








Friday, 12 April 2019

Extract NTFS permission ACL for Listed folder path

Short Story: - 
         
           I had received requirement to extract ACL (Permission entries )  information for the given folder paths which was indeed needed for the ACL clean-up project which we were running.

          So, what I did ???

Launch the "POWERSHELL ISE" and started thinking about the requirement. I know we can get the ACl information using "GET-ACL" cmdlet. So, it make easy for me to build a script with that main cmdlet.

 Challenge: 

           One challenge was to extracted information should be in Excel format with path information, ACLs with rights information

Solution: -

           I used the basic for loop method with Get-ACL cmdlet and I have to manipulate the output of cmdlet using Select with hastable customization.

           Since, most of the machine were not running PS version 3.0, I have not used the "Export-csv -append" parameter to append the each folder ACL information to CSV file

          Instead, i have to append information to the Variable and then finally at the end of the loop, Export the output to CSV file using Export-csv cmdlet

Powershell Script: -



<#
.SYNOPSIS
    List the folder permission entries for the given list of folders
   
.SYNTAX
    Script Execution Syntax is provided below. Please don't forgot create the Input file and call the input file during the script execution
   
    How to Execute the Script :
   
    .\ACL_Extract_RootFoldersonly.ps1 -InputFile .\folderlist.txt

     
.DESCRIPTION
   
    . This Script is designed for the requirement to get the list of ACLs in the project root directory for access clean-up purpose.
    . Script only looks for the
     
.PARAMETER
    -Inputfile
        This file should contain folder names each in separate line. If possible include full path or your have to copy the script location the folders are exist
        . This parameter Value is mandatory to be provided while executing the script.
   
    Ex:
    c:\projet\folder1
    c:\projet\folder1
 
     ( or )
   Folder1
   Folder2 


.EXAMPLE

    .\ACL_Extract_RootFoldersonly.ps1 -InputFile .\folderlist.txt


.Notes
   Script is created and tested in test facility. Ready all the information carefully and use in your environment with test users before
   using in Production.
   It works with Powershell Version 2.0

.Modifications
   Script Initially created by : Murugan Natarjaan / murugan.natarajan@outlook.com
   Date of Initial Version     : 04/Apr/2019
 
#>

Param(
   
    $InputFile = '.\folderlist.txt'
   
)

$folders = Get-Content $InputFile

# Loop each folder path and get the ACl information and store in the variable named "output" with append operation, so that it can be simply exported
# to CSV file for our requiremnet for easy view.

Foreach ($folder in $folders){
 
    $output+=Get-Acl $folder | select -ExpandProperty access | select @{label='FolderName';Expression={$folder}},identityreference,filesystemrights
     

}

# Every time the report.csv is replaced with latest content ( No append operation here )

$output | Export-Csv Report.csv -NoTypeInformation



User password expiry date identify ( Even if you have FPP deployed for user )

Short Story about issue: -

           Everyone might be already aware that we can get the basic information user attribute information using "net user" command,

           for example : Net User /dom mnatarajan

Which give useful information like when password last set, when it's expiring and when the password can be changeable all based on the password policy applied.

          I came across an issue that when I query similar information for an user where the specific "Fine-Grained Password policy" is applied, the native tool gives me the information for the "Default domain password policy" instead of FPP policy calculated information.

Solution: -

         To get the password expire date, i have to get few details of user and process to check whether FPP is applied or default password policy is applied and then calculate the password expire date for an user.

PS Script Detail: -


# Identify the Next possible password expire date for user

# Global Parameter defining, you can also execute script like below example
# Example: .\Calc_User_passwordExpiry_Date.ps1 -inputuser 'mnatarajan'
# Created by Murugan Natarajan /DXC
# Mail address: mnatarajan24@dxc.com

    param(
   
    $Inputuser = 'mnatarajan'

    )
   
    # Validate Simple check for user existance in domain, if does not exist, EXIT the script.


    If ((Get-Aduser $inputuser) -eq $null){

        Write-Output "$Inputuser does exist in default domain, validate user name in input"
        EXIT
       
    }
   
   
    # Check if user has FPP setup

    $fppcheck= Get-ADUserResultantPasswordPolicy $Inputuser
       
    # Calling user Password last set attribute

    $passlastset= Get-ADUser $Inputuser -pr passwordlastset | select -ExpandProperty passwordlastset

    # If User is not applied with FPP, then take value of default user password  to variable and compare with user last password set time

        If($fppcheck -eq $null)  {
       
            $DefaultCheck= Get-ADDefaultDomainPasswordPolicy

            $collectMaxpassage= $DefaultCheck.MaxPasswordAge.Days
            $DefaultUserPassExpireson = $passlastset.AddDays($collectMaxpassage)

            Write-Output "Password Expires for $Inputuser on $DefaultUserPassExpireson (Default Domain Password Policy)"

        }
       
        # If FPP is applied for the given user, then taken info from FPP and process with last password set time

        else {
       
            $Fppmaxpassage= $fppcheck.MaxPasswordAge.Days
            $FppuserPassExpire= $passlastset.AddDays($Fppmaxpassage)
            $Fppname = $Fppcheck.name
            Write-Output "Password Expires for $Inputuser on $FppuserPassExpire _FPP-Applied $Fppname"
       
        }





Wednesday, 16 August 2017

Delegate permission to retrieve the Bit-Locker keys



Hello Guys,

We started the work to clean up users from the privileged groups like “Domain Admins and Enterprises Admins” group.

Yes, it’s good idea to have only limited persons only on these groups. But lots of users who are removed from these groups started complaining that they lots their access to the shares, bit-locker key retrieval and unable to do basic tasks like password reset, unlock account and group membership changes.


So, as first step we granted the share and delegated rights for basic tasks, but I was only stuck with granting rights to Bit-Locker password key retrieval.

Have setup the Delegation of wizard at domain level to the particular group and granted the rights to Read permission to the ms-FVE-Recoveryinformaiton objects.

How to grant rights through Delegation wizard ?

1) Start the Delegation wizard at domain level





2) Select the Bit-Locker Support group


3) Select create custom task to delegate

                                                                                                                                                                       

4) Select the "msFVE-RecoveryInformation" in the "Only the following objects in the folder"


                                               
5) Select the "Read all properties"

                                      
6) Finish the Delegation wizard.

                                             
Now add the users required desktop admins to the Bit-Locker support group
Ask them to install RSAT tools for AD and Bit-locker support tools on their management system


Now, they should be able to view the Bit-Locker password information after launching the DSA.msc console. New tab should be visible in the console

Note:  You may noticed that there are no items in this view in the below snapshot, but it's ok because it's my test machine where Bit-locker is not installed.