Creating 1.5 million users in AD
Ever needed to create A LOT of user accounts?
Try this script: (uses Quest CmdLets)
Service Monitoring and Recovery with PowerShell
Recently, Symantec Backup Exec was crashing quite regularly on me.Every Saturday at 4am, the main Backup Exec service would coem crashing down, taking the weekly backups with it and then causing my Monday morning to be painful (unless whoever was on call managed to see that the backups had stopped).
I know that this sort of monitoring should be done with something like SCOM, but that wasn't something I could do in this situation.
The solution was a PowerShell script running hourly (or more or less depending on the needs) that would look at the running state of all the Backup Exec services and start any that were not running, as well as send the person on call an email to tell them something bad was happening.
Using my standard template (see previous postings), I added one parameter to the script, $query, which is simply the query string that I would pass to get the services I want to monitor. For example, a query string of "backup*" will return all the Backup Exec processes, a string of "spooler" would return the print spooler.
The body of the script is pretty simple:
Windows DNS and BIND Server together
Another one of my bulk DNS scripts.
This was a weird request however there were a number of requirements:
- Allow BIND servers running on Linux/Unix to take zone transfers of all production zones (forward and reverse), this should be limited to specific servers.
- BIND servers should only be allowed to request one transfers from specific servers
- Only authorised BIND servers should be permitted
- BIND servers SHOULD be listed in a name server query for a particular zone (that is, BIND servers should have an NS record)
The script is pretty simple:
DNS Cleanup - Removing an old DNS Server
The script that is outlined below was written very quickly one night. The issue was we had several old decomissioned/dead DNS servers in the environment, and a lot of DNS namespaces to remove them from (aproximately 10 forward and 20 reverse lookup zones). It should be noted that this script assumes we can make a change on a single master server and replication (hopefully AD Integrated) will take care of the rest.
Enjoy.
$masterdns = "<Primary DNS FQDN>"
$olddnshost = read-host "Enter new host name (FQDN)"
$enumzones = get-WMIObject -Computer $masterdns -Namespace "root\MicrosoftDNS" `
-Class "MicrosoftDNS_Zone"foreach ($zone in $enumzones)
{
if ($zone.zonetype -eq 1)
{
write-host ""
$name = $zone.namednscmd $masterdns /recorddelete $name "@" NS $olddnshost
Write-Host "NS Record for "$olddnshost " deleted from "$name
}}
Quest Active Directory CmdLets and Distribution Groups
All sysadmins will at soem point be required to clean up/report on Microsoft Exchange distribution groups within their organisation. Below are some notes I made as I was working on them recently.
Note: All of these use the Quest AD Cmdlets
I had a array of groups that had been passed to me ($groups), I wanted to add to that array the name of the user who manages that group, before passing the variable on to other things:
Function Get-ManagedbyName {
[cmdletbinding()]Param (
[Parameter(Position=0, Mandatory=$True, ValueFromPipeline=$True, `
HelpMessage="You must specify a QAD group object")]
[Quest.ActiveRoles.ArsPowerShellSnapIn.Data.ArsGroupObject]$group
)Begin {
Write-Verbose "Starting function"
}Process {
$managedby = $group.managedby
$managedname = ""
if (($managedby -eq "") -or ($managedby -eq $null)) {
$managedname = ""
} else {
$managedname = (get-qaduser $managedby).name
}
$group | Add-Member -MemberType NoteProperty -Name "ManagedbyName" `
-Value $managedname -passthru
}End {
Write-Verbose "Ending function"
}
An example of using this would be
$groups= <get your group>
$groups| Get-ManagedbyName
A cmdlet to hide groups from the global address list:
Function hide-distributionlist {
[cmdletbinding()]Param (
[Parameter(Position=0, Mandatory=$True, ValueFromPipeline=$True,
HelpMessage="You must specify a list of groups")]
[System.string[]]$groups
)Begin {
Write-Verbose "Starting hide-distributionlists"
}Process {
foreach ($group in $groups)
{
#move the group to:
Move-QADObject $group -newparentcontainer "OU=disabled mailing groups, `
OU=disabled users,OU=CSAU,DC=sunqld,DC=com,DC=au"
#hide from addresslist
set-qadgroup $group -objectattributes @{MSExchHideFromAddressLists=$true}
}
}
End {
Write-Verbose "Ending hide-distributionlists"
}}
Automating Nmap analysis with PowerShell
Nmap is one of the best tools in a sysadmin's toolkit; this powerful tool allows us to quickly determine what computers and devices are on our network, what software and operating systems are running.
In most environments, esp. when there are a large number of servers and workstations in quite a number of subnets, its handy for system administrators to be able to easily find a free IP address.
There have been several times when various security managers have requested to know the following items:
- All servers/workstations that are up
- Are the following services running: SSH, Telnet, FTP, HTTP, HTTPS, RDP, SMTP
- Is there anonymous FTP?
- Is there anonymous FTP uploads?
Nmap is obviously the tool to complete the task to find out this information. If we could automate this, then we could easily generate reports for upper management!
Thankfully, the guys over at SANS have already completed most of the work for us. In the post: PowerShell Script To Parse nmap XML Output, the provide a script which gets Nmap XML output and makes it into a format that allows any powershell user to manipulate the results using all the usual commands (format-table, format-list, where-object, select-object).
I developed a simple script to find IP addresses that were in use and provide a simple output that any system administrator or service desk operator could read. The script is simple, and does the following tasks for each subject listed in an array:
- Make a user friendly filename
- Run nmap to perform a number of ICMP and TCP scans to find servers that are up (I recommend TCP SYN scanning on top of ICMP Ping to ensure you find firewall protected servers and workstations)
- Parse the results of nmap and put them into a file in a more friendly format
The script looks like this:
nmap Command breakdown:
-PS20,21,22,23,25,3389,80,443,8080 is a TCP SYN Ping sweep of the subnet of ports 20, 21, 22 etc
-PE is ICMP ping (usual ping command)
-R is perform a reverse DNS look up
--dns-servers is specifying all of our DNS servers (incase you have reverse lookup zones across differing DNS servers)
-p 20,21,22,23,25,3389,80,443,8080 we want to scan these ports for possible reports later on
-oX $nmapfile --no-stylesheet outout the results to the filename and don't use a XML sylesheet
-A enable all advanced options
-v we want verbose output for reporting.
We end with the subnet we want to scan.
PowerShell RoboCopy Wrapper
So I find myself copying files from point A to point B on a regular basis, so much so, that I find myself using robocopy in a Windows scheduled task. The problem with this approach, is that there isn't many easy ways of working out if it worked, or worse, if something bad has happened!
I bashed out a script several years ago, and finally updated it to make use of the template that I posted up previous.
There are a few things to note with the script:
- I always check if the source and destination exist, and report an error if they don't
- My scripts always use the /MIR command, and limit retries to 3
- Robocopy return codes:
0: Completed sucessfully, but didn't copy any files
1: Completed sucessfully and copied files
rest: some error has occured
The bulk of the code is:
#robocopy task
$result = robocopy $source $destination /MIR /R:3
#robocopy sucess is: 0: no errors, but no copying done
# 1: one or more files were copied sucessfully
#check there were no errors in the robo copy
if ($lastexitcode -gt 1)
{
if ($lastexitcode -eq 0)
{
$messagebody = "Robocopy completed but no files copied! `n"
foreach ($x in $result) {$messagebody = $messagebody + $x + "`n"}
send-email $messagebody $false
} elseif ($lastexitcode -eq 1)
{
#do nothing, it worked
} else {
$messagebody = "Robocopy returned an unknown error! `n"
foreach ($x in $result) {$messagebody = $messagebody + $x + "`n"}
send-email $messagebody $false
exit 3
}
}
The entire script is in the samples section, here.
Powershell Script Template
Just a quick post to cover layout/format of all PowerShell scripts I write.
This default template ensures that a sufficient amount level of of quality is ensured in all scripts. There are several things you will notice:
- All scripts start with param definitions, which include items for the functionality for that script (both mandatory and option) as well as variables used to support features other basic functions
- Email alerting on success of failure with option to turn off or on both, either, or no email alerts
- I use exit calls, I know this is probably considered bad, but as you can see, it makes it easier to troubleshoot
And here it is (you can download it here):
# ==============================================================================================
#
# Microsoft PowerShell Source File -- Created with SAPIEN Technologies PrimalScript 2009
#
# NAME: <name of script which will be helpful>
#
# AUTHOR: <author>
# DATE : <date>
#
# COMMENT: <Step through what this script does
#
# ==============================================================================================
#<place comments used to assist in the calling of the script
param(
#<application specific params>
#<email and alerting params>
[Parameter(Position=3, Mandatory=$false, HelpMessage="Specify email alert recipient address")]$recipient="[email protected]",
[Parameter(Position=4, Mandatory=$false, HelpMessage="Specify email alert from address")]$from="[email protected]",
[Parameter(Position=5, Mandatory=$false, HelpMessage="Specify smtp server name/ip")]$smtpserver="smtp.server.com",
[Parameter(Position=6, Mandatory=$false, HelpMessage="Alert on sucessfuly copy")]$emailonsuccess=$true,
[Parameter(Position=7, Mandatory=$false, HelpMessage="alert on failure of copy")]$emailonfailure=$true,
[Parameter(Position=8, Mandatory=$false, HelpMessage="alert email subject")]$emailsubject="<change to be helpful subject>"
)
#
#variable declarations
function send-email ($body, $success)
{
#incase we are troublshooting, output the body here
$body
$error.clear()
#if it is sucessful
if ($success)
{
#if we want a successful emails
if ($emailonsuccess)
{
$subject = $emailsubject + "- Success"
Send-MailMessage -To $recipient -From $from -SmtpServer $smtpserver -Subject $subject -Body $body -bodyashtml
}
}
else #if unsuccessful
{
#if we want emails on failure
if ($emailonfailure)
{
$subject = $emailsubject + "- Failure"
Send-MailMessage -To $recipient -From $from -SmtpServer $smtpserver -Subject $subject -Body $body -bodyashtml
}
}
if ($error)
{
"Unable to send an email"
exit 666
}
}
#
# If we expect a crash/error here is an example (this is using $error but it could be try catch or based on $lastexitcode for external calls
#
$error.clear()
#do something bad
somethingbad()
if ($error)
{
send-email "<sad>" $false
exit 7
}
#email that we got here successfully
send-email "<HAPPY>" $true