



I should have posted this a long, long time ago…but forgot. Until I got a comment from dvdor about it.
In Active Directory, we set the “Managed By” field on all of the servers we manage to our primary, non-admin account. This makes it easy for people to find out who manages what servers. It also makes it easy to do batch upgrades/file copies/whatever to your own servers.
This script, get-servernames.ps1, has a single parameter. -username. It just returns a text list of your servers…no objects or anything. I didn’t see the need, since all I wanted was the names.
Syntax: .\get-servernames.ps1 -username tmoser
Summary: Will take in your username (samaccountname) and first search AD for it. If found, it will search AD for all computer objects that have your account in the “Managed By” field. Those are returned in a list.
Uses: Things like: .\get-servernames.ps1 -username tmoser | foreach { copy-item C:\temp\somefile.txt \\$_\c$\temp\somefile.txt }
You can use it for error log checking, copying files, running remote psexec commands…anything, really.
param($username)
$root = new-object DirectoryServices.DirectoryEntry 'LDAP://dc=yourdomain,dc=com'
$searcher = new-object DirectoryServices.DirectorySearcher
$searcher.SearchRoot = $root
$searcher.Filter = "(samaccountname=$username)"
$results = $searcher.findOne()
if ($results -eq $null) {
write-host -fore 'blue' -back 'white' "`"$($username)`" not found"
exit(1)
}
else {
$dn = $results.GetDirectoryEntry().distinguishedname
$searcher.Filter = "(&(samaccounttype=805306369)(managedby=$($dn)))"
$servers = $searcher.FindAll()
if ($($servers.count) -gt 0) {
foreach ($server in $servers) { write-output "$($server.GetDirectoryEntry().cn)" }
}
}




I had an issue today where I needed to find the frequency of an error on some of my VMs. It seems like I get VMSCSI errors at the same time each which (which probably means high SAN activity, but I’m trying to nail everything down). Either way, I needed to check all of my event logs for EventID 11 and 15. It’s slow…and by slow I mean it took about 30 minutes to scan 10 or so VMs…but it works, and I was able to get a decent idea of the times I’m seeing these errors.
$servers = .\getservernames.ps1 Tom
foreach ($server in $servers)
{
if ((get-wmiobject -computer $server win32_computersystem).manufacturer -eq "VMware, Inc.")
{
get-wmiobject -query
"select * from Win32_NTLogEvent where LogFile = 'System' AND EventCode = 11
OR EventCode = 15" |
foreach { add-content c:\temp\$server.log "$_.timegenerated - $_.eventcode" }
}
}
Aaaand, it’ll return logs for each server, with a time stamp, the event ID, and nothing more. Quick, dirty, but took me 5 minutes and got the info I needed…30 minutes later :p There’s probably a better way. I’ll have to see what I can come up with.




So, with PowerShell 2.0 CTP’s arrival, and me finally having some time to mess around with some of the new features, here’s my previous (and first popular) post re-hashed for PowerShell 2.0 CTP. This will only work on machines with WS-Management installed, so it probably won’t work on most of your machines (unless you’ve deployed it), but it works well in my little test world. It utilizes two new features. These features are the [ADSISearcher] and Invoke-Expression. Instead of creating all of the Directory Service objects each time, you can just cast the ASDISearcher type and you’re done. Invoke-Expression allows you to use the -computer parameter and pass one, or many, computers to the cmdlet. I chose to use a single command here.
[adsisearcher]$searcher = “LDAP://dc=foo,dc=bar,dc=com”
$searcher.filter = “(objectclass=computer)”
foreach ($machine in ($searcher.findall()))
{
invoke-expression -computer $machine.properties.cn -command ”c:\windows\`$NtUninstallKB917013`$\spuninst\spuninst.exe /q /norestart”
}
I haven’t had a chance to test it, but you could use mutiple computers. We could change the foreach loop to write to a text file, then read that file for the computer names.
...
foreach ($machine in ($searcher.findall())){ add-content c:\temp\machines.txt "$($machine.properties.cn)" }
invoke-expression -computer (get-content c:\temp\machines.txt) -command "c:\windows\`$NtUninstallKB917013`$\spuninst\spuninst.exe /q /norestart"
That’ll kick off on 50 machines at a time. You can adjust that via the -ThrottleLimit parameter, and make it more or less, depending on bandwidth, CPU power, etc.
As you can see, I tend to learn better by example or by practical application. You’ll never see me write a book :) More soon!!




I don’t understand the big issue with the accidental release of WDS (Windows Desktop Search) via WSUS (here). It wasn’t like MS said “Muhuhahaha, let’s release WDS to the masses via WSUS!” I mean…why? There’s no compelling reason for this besides a simple mistake. Now, the fact that the mistake was made is a little scary. I don’t want some blue-screen causing driver or security update released to 500 servers. That might wreck my month…no, year. Then again, how many critical servers are set to auto-update? Test and QA boxes, but never production, unless you’re load balanced (ie, IIS boxes), and can stagger update times. At least that’s how I see it…
Removal was pretty easy, too. Altiris works wonders. But, let’s say you don’t have Altiris. You could use (ready for this?) PowerShell. They provide the removal instructions on the WDS blog entry. Using another handy utility, PSEXEC, you could very easily run a script to remove WDS. It might take a while, depending on the number of machines, but it’ll work…and without much effort.
For the sake of argument (and typing), let’s say it went to every box on your domain, server and desktop. This will only return 1,000 objects, so you’ll need to break it out by OU or some other method if you have more than that. Here’s my remove wds script (excuse the formatting…)
$root = new-object DirectoryServices.DirectoryEntry
$searcher = new-object DirectoryServices.DirectorySearcher
$searcher.SearchRoot = $root
$searcher.Filter = "(samaccounttype=805306369)"
$machines = $searcher.FindAll()
foreach ($machine in $machines)
{
psexec.exe "\\$($machine.properties.cn)" -d - c:\windows\`$NtUninstallKB917013`$\spuninst\spuninst.exe /q /norestart
#run PSEXEC, execute sp uninstaller quietly, with no restart. PSEXEC will not wait for app to finish
#and will only wait 5 seconds before timing out when attempting to run the remote command
}
Now, you’ve kicked off the task to remove the update from all of your machines…or 1,000 of them.




Here’s the script I metioned a few days ago. I wrote this a while back (Pre-RC0, I think).
Anyway, if you’ve got a bunch of servers that you need to perform a common task on (copy files, check event logs, etc), this is handy…however, it only works if you’ve got the Managed By field set in AD. Otherwise, you’re SOL. First, it makes sure the account name given exists in AD, then searches AD for and computer objects managed by that account. It uses write-output to return the list of servers. It outputs strings, not objects, since that’s all I needed out of it.
Syntax is: .\get-servernames.ps1 <samaccountname>
$root = new-object DirectoryServices.DirectoryEntry 'LDAP://dc=foo,dc=bar,dc=com'
$searcher = new-object DirectoryServices.DirectorySearcher
$searcher.SearchRoot = $root
$searcher.Filter = "(samaccountname=$($args[0]))”
$results = $searcher.findOne()
if ($results -eq $null) {
write-host -fore ‘blue’ -back ‘white’ “`”$($args[0])`” not found”
exit(1)
}
else {
$dn = $results.GetDirectoryEntry().distinguishedname
$searcher.Filter = “(&(samaccounttype=805306369)(managedby=$($dn)))”
$servers = $searcher.FindAll()
if ($($servers.count) -gt 0) {
foreach ($server in $servers) { write-output “$($server.GetDirectoryEntry().cn)” }
}
}
As I mentioned, this is pretty handy for copying files to groups of servers, checking error logs via psloglist, doing inventory, and more.




No. This script doesn’t do the updates for you, as awesome as that would be. I have a bunch of boxes that I have to do firmware updates on tonight. Apparently the Dell PERC4 has an issue on a certain firmware revision that will cause arrays of 5 or more disks in RAID 5 or 50 to fail during rebuild after replacing a failed disk (and I have a disk to replace). My array isn’t 5 disks but I’m playing it safe, as this is a production server. So, I thought “I don’t want to have to hit this from a file share tonight, or have to copy it tonight…” Go go lazy powers. I wanted to copy this to all of my DELL boxes, but not the VMs or HP machines. Enter, PowerShell.
.\get-servernames.ps1 <samname>
| foreach {
if ((get-wmiobject -computer $_ win32_computersystem).manufacturer -contains “*Dell*”) {
copy-item c:\SUU \\$_\c$\suu -recurse -force
}
}
More on get-servernames.ps1 later. But, now my SUU is on all of the servers and waiting for me tonight. I kicked it off and went home. And excuse the formatting, the layout is a work in progress!


More Options ...

Categories
Tag Cloud
Blog RSS
Comments RSS


Void
Life « Default
Earth
Wind
Water
Fire
Light 