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:
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.