Powershell

Showing posts with label Active Directory. Show all posts
Showing posts with label Active Directory. Show all posts

Friday, March 1, 2019

Get MyDocument and Desktop Folder size for all computer in the network


This Script will read the computer list from a CSV file and scan all the computer in the list to get the current size for MyDocumet and Desktop folder in the remote PC.
This script is very useful to size your VDI environment and get an idea about the expected user profile, especially when all the users are using regularly PC and storing all their content on the desktop and MyDocuments
I chose to get the information from the CSV file as I request from the network team for the most recent computers list which is connected to the network. the active directory can contain some old computer object or test pc, which will increase the percentage of failed scan. Anyway, if you prefer to get the list from AD you still can do it by using 
Get-ADComputer -filter * | Export-Csv -NoTypeInformation -Path c:\temp.csv




#############################################################
# This Script is written by Faris Malaeb
# Feel free and contact me farisnt@yahoo.com, farisnt@gmail.com
# http://farisnt.blogspot.com/
#
#This script will scan the network and get the users desktop and mydocument profile size
#This Script will help you in giving you an idea about the users data
# I wrote this script as I needed to know how much users have in their desktop and MyDocument folder
#These data should be moved to the servers as a part of VDI Project implementation.
#
#
# Get the computer objects
# Tested on Windows 10
#
#To use the Script .\Get-DesktopnDocs.ps1 -FullPathForSoruce C:\PCList.csv -ResultDestination C:\MyFinzalResult.csv
#You can use the -Verbose parameter for more information during the runtime
#############################################################


param(
[parameter(Mandatory=$False)]$FullPathForSoruce="C:\PCs.csv",
[parameter(Mandatory=$False)]$ResultDestination="C:\MyFinzalResult.csv"
)
$Collection=Get-Content -Path $FullPathForSoruce
#The final result will be added to this array
$FullResult=@()

try{
    Write-Host "Validating the destination path $ResultDestination" -ForegroundColor Green
    Add-Content -Path $ResultDestination -Value "temp"
    Remove-Item $ResultDestination
    }
catch{
    Write-Host "Failed to write to path $ResultDestination... Exiting " $_.exception.message
    break
    }


#Looping through all the computer object
foreach($SinglePC in $Collection){


#Checking if the computer is alive or dead
    try{ (Test-Connection -ComputerName $SinglePC -Count 1 -ErrorAction Stop |Out-Null)

        #I need to have an object which contain ComputerName, Deskop, MyDocument and Username properties
        #I will name this object as TotalResult
        $totalresult =New-Object psobject
        $totalresult | Add-Member -NotePropertyName ComputerName -NotePropertyValue ""
        $totalresult | Add-Member -NotePropertyName Desktop -NotePropertyValue ""
        $totalresult | Add-Member -NotePropertyName MyDocument -NotePropertyValue ""
        $totalresult | Add-Member -NotePropertyName username -NotePropertyValue ""
        $totalresult.ComputerName= $SinglePC

        #Each properties of the newly created object will contain the output from a command invokation
        #Getting the username of the active user from the remote machine.
        #I am getting the username through reading the running process which run under the user context.
        #My Domain name is Domain-local, and as the client OS only support one login, so all the process should have the current active user
        #I used the $env:USERDOMAIN System Variable to get the domain name, lets assume that my domain is named as Domain-Local
        #After getting the list of processes running under the username Domain-local\..., I select the first Item in the array and removing the domain name
        #This will only return the username, and then store the result in the $TotalResult.Username Properties
        $ScriptToExecute={
        ((Get-Process -IncludeUserName |where {$_.username -like "$env:USERDOMAIN*"})[0]).username.substring(([int]$env:USERDOMAIN.Length+1))
        }
        $totalresult.username=invoke-command -ComputerName $SinglePC -ScriptBlock $ScriptToExecute

        #The command which will be invoked on the remote computer
        $ScriptToExecute= {
        $UserNViaProcess =$args[0] #read the argument that will be passed to the script block through the invoke-command -ArgumentList property
        #The Lines below will get the Desktop items which have the extension below.
        #the Measure-Object will calculate the value a group based on numeric property, and in our case the value I want to measure is the Length
        #After the calculation I devide the value by 1GB to get the result in GB
        ((Get-ChildItem -Path "C:\users\$UserNViaProcess\Desktop" -Recurse -Include @("*.docx","*.xlsx","*.pptx","*.txt","*.mmp","*.jpg","*.png","*.pdf","*.vsdx")|Measure-Object -Sum Length).Sum /1GB)
        }
        #Executing the remote command invoke and passing the arguament list, which is the username
        $totalresult.Desktop=invoke-command -ComputerName $SinglePC -ScriptBlock $ScriptToExecute -ArgumentList $totalresult.username

                                                                           
        $ScriptToExecute={
        $UserNViaProcess =$args[0]
        ((Get-ChildItem -Path "C:\users\$UserNViaProcess\Documents" -Recurse -Include @("*.docx","*.xlsx","*.pptx","*.txt","*.mmp","*.jpg","*.png","*.pdf","*.vsdx") |Measure-Object -Sum Length).Sum /1GB)
        }
        $totalresult.MyDocument=invoke-command -ComputerName $SinglePC -ScriptBlock $ScriptToExecute -ArgumentList $totalresult.username
 
        #Display the result in the console
        $totalresult
        #Adding the Result to the array
        $FullResult+=$totalresult

        }


    Catch {

            Write-Host "I failed on " $SinglePC " Error is " $_.exception.message
         }

    Finally{
    $FullResult | Export-Csv $ResultDestination -NoTypeInformation

        }
}




Sunday, February 16, 2014

Why AD User account locked out

Why My Account is locked out frequently???
This is one of the most common questions, users are complaining that their account is being locked and they even did not type their password.
Today I will talk about this problem and how can you fix it, I saw a lot of blogs and software that report from where the account is locked, but in some cases you need to know more.

The First Question is: From where this account is being locked out ??
There are several software (Some are free and other paid) that can tell you from which computer or device this account get locked.
One of the simplest way and its free is to search in DC Security Eventlog for the following
Event ID: 4740
Event source: Microsoft Windows security auditing
In this log what you will see is this

Notice that the Caller Computer Name is the computer or device that cause the account to be locked, In my case its Win7x86.
Now we have the computer name, but where in this computer you should search, there are several places that could have the old or wrong password saved.!!, it could be :
  1. Map Drive
  2. Schedule Task
  3. Windows Service
  4. Saved credential in user Credential Manager in Control panel
  5. Password for Mail account that is stored on user Mobile device 
  6. and several other location.
To save some time there is a good tool (Free Trail)
http://www.netwrix.com/account_lockout_troubleshooting.html (Account Lockout Examiner)  for querying the computer name that causing the account lock and also perform some basic check on the target machine to analyze what may cause the lock out "schedule task, MAP Drive, Windows Services...".

This seem to be good, but not always give you the right answer
Sometime its something else, not Windows Service or schedule task or any of the built in fixes. so what should you do..
In this case you will need to monitor Failed Audit for:
- Audit process tracking. ( not required but it will give you more information)
- Audit logon events.
Run Gpedit.msc on the local computer and navigate to:
Windows Settings \ Security Settings \ Local Policies \ Audit Policy

And from there you will double click on  Audit logon events and put a check Success , Failure
Set back and relax, and wait for the next lockout and once it happens review Client Machine Audit log and check the failed Log you will see something like this

As you can see and in my case the process that is using the old password is Sharepoint Search component (mssdmn.exe). so simply update the password to a new password from sharepoint site.

This is the best way to get put your finger on the main problem. I hope you like this


Wednesday, November 20, 2013

Add a User Profile Picture in Active Directory

Good day.
Sometime you need to add a picture for your users accounts in active directory, like this
by the way, this is not me :) 

Today I will talk about how to do this step by step.
First, What you need to have this:

  1. First to have full control on AD users account, I will tell you which value we will modify later.
  2. You will need to download a DLL file ADExt.dll download Here (Mirror Here).
  3. To be an administrator on the server
So let start.
After you download the DLL you will need to install it using the InstallUtil.exe which located :

For 32 bit OS: 
%WinDir%\Microsoft.NET\Framework\v2.0.50727>
For 64 Bit OS:
%WinDir%\Microsoft.NET\Framework64\v2.0.50727>
I had the ADExt.dll placed on the root of my C Drive so I write
InstallUtil.exe c:\AdExt.dll
The output will be like this picture
Make sure that the result are success, if you get an Access Denied, simply run right click on CMD and select Run as Administrator

We are finished, was it hard :)
Open your active directory and you will find new tab named "Photo", there you can add/update/remove the user picture.
The recommended picture setting should be 10K or less with size 96x96, but using this dll you can add what you want, the dll will manage the size and the view.
But just remember that bigger picture = slower respone
Also think of having hundred of pictures for hundred of employees, these picture (data) will also be replicated.
When adding a picture you are actually adding the value to the following attribs: jpegPhoto for the picture and thumbnailPhoto, this is the default location for users picture and what the DLL do is simply read and render this picture, as the picture is stored in hex value.
you can change the value format to binary/octal/decimal 

You can also use Powershell to update the picture value
Set-ADUser Mary-Replace @{jpegPhoto=([byte[]](Get-Content "C:\pic.jpg" -Encoding byte))}

Uninstall:
You can uninstall the DLL using the following command
InstallUtil.exe /u c:\AdExt.dll

I hope you like this post.

Friday, November 15, 2013

PowerShell: Get a list of users who had Email Address don't complies with the company email address policy

In all organization there are a policy for almost everything, including the email address for the employees.
Each employee should have an email address with a specific format, like FirstName DOT LastName@Domain.com , or FirstLetter of FirstName DOT Lastname @Domain.com.
But sometime you find that there are some users dont complies with the policy, maybe a previous IT create them or miss type or miss configuration of your mail server, so you want to know these accounts.
In my Powershell script I will search for all users with email address dont match the following policy
Firstletter of Firstname DOT Lastname@Domain.com
so here we go
#clear the screen
cls
#Get a list and some details for all the users in my active directory
#I used the filter userAccountControl to get a list of the active /Enabled users account
#I dont want the result to include any disabled users
$alluserdetails=Get-ADUser -Properties Givenname,sn,sAmaccountname,mail,displayname,userAccountControl -Filter{userAccountControl -ne 514} | select Givenname,sn,sAmaccountname,mail,displayname,userAccountControl
foreach ($useraccount in $alluserdetails){
# What I will do is :
# - Read each user account and take the First Letter of his First name 
# - Add a DOT "."
# - Add the full last name + including the domain name
# Each user in my AD should have an Email address that match this policy
$surname=$useraccount.sn
$firstname=$useraccount.Givenname.get_Chars(0)
$newemailaddress=($firstname+"."+$surname+"@domain.com").ToLower()

# I will compare between the current Email address the user have with the one that complies with the policy
#if the $newemailaddress (the correct Email) do not equal $useraccount.mail (the one he had)
# Powershell will right the output
#its possible to change this Email, but first you need to know what Email service you are using and how to modify it by PS
if ($newemailaddress -notlike $useraccount.mail){
Write-Host $useraccount.displayname 
} 
}


Easy yes? , hope so.
if there is anything not clear, just comment, and if its all clear, simple like and share it
Thanks

Sunday, November 10, 2013

Scan your network for open port and take action against it using powershell

Good day
For some reason you may need to run an IP Scanner on your network, most of IP scanner can also perform a port scan, but I did not find free one that can make action against the open port, like test SSL version on the running web server, or get information about the running web service or any other action.
So I decide to write my own script and share it with you.

cls
#for me I just want to get a list of computers that are running Windows 2008.
#You can cancel or modify the filter
#All the result will be loaded to a variable named as allservers
$allservers=Get-ADComputer -Properties name,operatingSystem -Filter{operatingSystem -like "*2008*"}
foreach($singleServer in $allservers){
$socket=New-Object net.Sockets.TcpClient

#its possible to use IF insted of TRY, but you will get an error when the connection fail, so its recommend to use Try/Catch/Finally
#Try Function will be used to initial the connection
#Good information about Try/Catch/Finally Here

    Try{
    #The created Socket will be used to connect to the server on port 443
        $socket.Connect($singleServer.Name,443)
        Write-Host "The port on " $singleServer.Name " is " -NoNewline
        Write-Host "open" -ForegroundColor Green
        C:\SSLScan.exe $singleServer.name
                
            }
        #Use Catch to get the System error
        Catch [system.exception]{
        Write-Host "The port on " $singleServer.Name " is " -NoNewline
        Write-Host "Closed" -ForegroundColor red
        
        }
        
}



I hope you like this script, Please like the page and share it :)
Thanks for reading

Thursday, October 10, 2013

Get A list of Users with Password expire in 2 days and notify them by Email

My Company policy do not allow any user with "Password Never Expire" except for Services access, All other users (human being) must change their password every 30 days.
So one of the main problem is that there are several users in travel and need to  view their emails using mobile client application which dont have a password expir-ation track, so I write this script that will get a list of users that has been using his password for more than 27 day and report

#I like to clear the screen before starting
cls
#The NeverUser value will hold the Enabled users information only
#this Done by using the userAccountControl attrib, if this attrib is 512 it mean that the account is Enabled
#If This value is 514 this mean that the account is disabled
$NeverUser=Get-ADUser -Properties displayname,sAmAccountName,pwdlastset,mail  -Filter{userAccountControl -eq 512} -SearchBase "OU=Employees,DC=Domain,DC=local" | select displayname,sAmAccountName,pwdlastset,mail

#Now I will start reading the value in the NeverUser
Foreach($SingleUser in $NeverUser){
#$First Date will hold the Last date the user set his password
$FirstDate=[datetime]::FromFileTime($SingleUser.pwdlastset)
#SecondDate will hold the value of the current date, you will know why in the next line
$SecondDate= Get-Date
#the calculation I used is to subtract the current date from the date when the user set his password
#the result will be the number of days the user is using the current password
$Result= $SecondDate -$FirstDate
#In my example I will generate a list of users who use their password for a period between 27 and 28 days, you may ask why? 
# First no need to inform a user with an already expired password that his       password will expire soon, as its already expire and he can not login
# Disabled user object may have the pwdLastSet very high (even i exclude them    using the Filter in Get-ADuser)
#This script is made to run everyday, without this restriction, the script will  send the user emails regarding their password till forever come and this is not  needed
if ($Result.Days -gt 26 -and $Result.days -le 29){
$ManyDays =30 - $Result.Days
#The Email Body, you can make it what ever you want
$EmailMessage ="Good day 
Your Password will Exipre in $ManyDays."
#Send-MailMessage used to send an Email message, you can also include attachment if you want  
Send-MailMessage -to $SingleUser.mail -From "" -Subject "Please Change your password" -Body $EmailMessage -SmtpServer "Your.Mail.Server"
} }

Saturday, September 28, 2013

How to search GPO for policy

Its really annoying when you need a specific GPO policy and you can not remember or find it, even you are sure that its exist.
Also sometime you need a policy that talk about (for example: firewall) and you don't know the entire policy name.
These are some of the cases that cause most system administrators hate to work with GPMC as there is no search or filtering in it.
Using Windows 2008 GPMC will allow you to filter and find a specific policy, how. here we go

  1. Open GPMC
  2. Navigate to Computer Configuration / User Configuration
  3. Click on Policies
  4. Right Click on Administrative Templates and select Filter Options...


In the Filter Windows, just type the policy you are looking for (I write Firewall) and click OK





















Once, you click OK, all the policy that contain the word "Firewall" will show up, for easier view, click on All Settings



Hope you like this,
Please support me by sharing or commenting


Tuesday, August 27, 2013

Get Obsolete Computer Object And Move them, Using PowerShell

Using this script you will be able to get all the computer Object in your AD, read the LastloginTimeStamp


import-module activedirectory #Add Active Directory Module to powershell
cls #Clear the console
$now=Get-Date #get the current Date
$now=$now.AddMonths(-7) #7 Month Ago
$Servers=Get-ADComputer -Properties lastLogonTimestamp -Filter {lastLogonTimestamp -lt $now}| select name,@{N='lastLogonTimestamp'; E={[DateTime]::FromFileTime($_.lastLogonTimestamp)}}
#filter the returned result to store only computer objects with LastloginTimeStamp before 7 month, I will read the lastLogonTimeStamp for each computer along with the Computer Name (Note: the -lt mean Less Than) 
foreach ($SingleServer in $Servers){ # to read each object in the $Server Variable 
$ODN = Get-ADComputer -Identity $SingleServer.name -Properties distinguishedName | select distinguishedName #We will need to get each computer DN and pass it to Move-ADObject, as Move-ADObject can not read computer name, it must read DN 
Move-ADObject $ODN.distinguishedName -TargetPath "OU=Disabled Objects,DC=Domain,DC=local"
}


you may get an error when running this script telling Cannot validate argument on parameter 'Identity'. The argument is null. This is because the returned result from $ODN=Get-ADComputer is Null as there is no computer which have LastloginTimeStamp value match the filter.

Like it, Please comment and share :)