Creating an Organizational Chart Using Powershell

 

There are many properties of a user account that are neglected and left untouched most of the times, like Description and Manager fields, in the Active Directory domain.

If we enter relevant info into these fields, we can get more information about user; its title, its manager and its direct reports.

On the other hand, it is understandable too not to enter such info because info about users changes frequently so, it must be updated periodically.

But let’s assume we have domain that those info about users entered correctly:

In the above figure, description field shows that there are a CEO, some VPs and Directors. The rest are the soldiers.

And, in addition to the Description field, Manager field for users is entered correctly too, like in the following figure:

Then the following code will create a nice organizational chart:

$list=get-aduser -filter * -Properties * | select name,description,manager #get the users’ name,description and manager properties

New-HTML -OnlIne -FIlePath $PSScrIptRootMyDIagram.html {

New-HTMLDiagram {

New-DiagramOptionsLayout -HierarchicalEnabled $true

New-DiagramOptionsPhysics -Enabled $true -HierarchicalRepulsionAvoidOverlap 1 -HierarchicalRepulsionNodeDistance 100

$list | foreach {

$desc=$_.description

$nameuser=$_.name

switch ($desc){

"ceo" {new-diagramnode -label $nameuser -level 0}

"vp" {new-diagramnode -label $nameuser -level 1}

"director" {new-diagramnode -label $nameuser -level 2}

default {new-diagramnode -label $nameuser -level 3}

}

}

$list | foreach {

$manag=$_.manager -replace "cn=" -replace "ou=" #get rid of cn and ou statements in the manager field

$manag=$manag.substring(0,$manag.indexof(",")) #take upto the first comma

$nameuser=$_.name

new-diagramlink -from $nameuser -to $manag

}

}

}-ShowHTML

Do not forget to install the necessary module first, if you didnot do it before:

Install-Module PSWriteHTML

The chart will be:

 

 

Resetting Local Administrator Passwords

Resetting the local administrator passwords has always been problematic.

I frequently used a computer startup script that reset passwords.

It was easy; it contained a single command: Net user administrator newPasswordWhateverItIs

The problem with this solution is that the script is a simple text file and it is placed in the Sysvol Folder that everybody can reach and read the new password.

So, a new technique must be found.

Microsoft has a good solution: Local Administrator Password Solution (LAPS)

LAPS modifies schema, creates new attributes, also installs a client side extension.

Then, local administrator password can be changed in bulk, to be unique to each machine.

New password is then transferred to a DC over an encrypted channel.

And the password attribute can be read by only specified admins.

LAPS is somewhat complicated at the same time: Installation of client side extensions, modifying schema, assigning permissions, etc…

 

So, I created a new solution to reset the local admin passwords.

This solution has its own drawbacks.

First, the new password is not transferred to anywhere!

After resetting the password, no one knows it!

But most of the times, not knowing local admin password may have its advantages.

Domain admins can access the machines without knowing its local admin password anyway.

Only case the unknown local admin password may create problems is when the connection (trust relationship) of the machine with the domain is broken.

In such a case, you need to logon to that machine as a local admin.

But in those times, we can easily reset this password using many techniques.

Ok, if you accept these shortcomings, you can examine the solution.

Solution consists of creating a random password and assigning this password to the administrator user.

 

I took random password generation part from a Stackoverflow post:

https://stackoverflow.com/questions/37256154/powershell-password-generator-how-to-always-include-number-in-string

I wanted this code to run only once.

So, at the beginning, I check the existence of a file with a name containing the local machine name.

If there is the specified file, then it means, code was run and skip the resetting.

If there is no such file, I create a random password, assign it, then I create the computername-file and also append the name to another text file to see the affected machines.

Files will be created in a share. On the share, permissions must be Everyone, Change.

Hackers can read the content of the files, but they cannot see the new passwords.

And when you want to reset the passwords again, you just need to delete the files under that share.

Code:

if (test-path \\servername\ortak\$env:computername.txt)

{#doNothing} else

{

$punc = 46..46

$digits = 48..57

$letters = 65..90 + 97..122

$YouShallNotPass = get-random -count 15 `

-input ($punc + $digits + $letters) |

% -begin { $aa = $null } `

-process {$aa += [char]$_} `

-end {$aa}

net user administrator $YouShallNotPass

“OK” | out-file \\servername\ortak\$env:computername.txt

$env:computername | out-file \\servername\ortak\list.txt -append

}

Stopping a Process Using Its Certificate

Recently, I’m asked to find a way to prevent "ProcessHacker" program, a popular program to manage running processes.

First, I wanted to use Software Restriction Policies in Group Policy, using the hash values of the program.

But I’m told that the program is frequently updated, so its hash value changes, therefore software restriction policy using the hashname cannot be a solution.

Software restriction policies can restrict a folder so that no program can be run in that folder but ProcessHacker has no installation folder, so this option is invalid also.

The unchanged and cannot be easily changed parameter is the certificate used to sign the code of the program.

This certificate has a subject line reading as "CN=Wen Jia Liu, O=Wen Jia Liu, L=Sydney, S=New South Wales, C=AU".

If we scan all the running tasks, check their certificates to see if its subject line is so and so, then we can stop that task.

The following code just does it:

get-process | foreach {

$exename=$_.path

$sert=(Get-AuthenticodeSignature $exename).signercertificate.subject

if ($sert -eq "CN=Wen Jia Liu, O=Wen Jia Liu, L=Sydney, S=New South Wales, C=AU") {stop-process $_}

}

This code can be run locally or remotely and can also be scheduled, so it stops the process not once.

 If we assume mainly a single user uses a machine, then we can find their profile folder size using the folllowing code:

 

Reporting the User Profile Folder Size

$profilsize=Get-ChildItem $env:userprofile -recurse | Measure-Object -property length -sum
$profilsize=$profilsize/1GB

$Info=$env:computername+" "+$env:username+" "+(($profilsize).sum).tostring()
$info | out-file \\servername\ortak\list.txt -append

This code must be run as a logon script.

So, when a user logons to their machine, profile size is reported to a file in a share.