Friday, November 27, 2009

Running Repetitive Remote Tasks

In my support of computers, I very often have to run scripts to perform tasks on all the machines in my area. Sometimes I have to query the Registry for the version of Adobe Reader or Acrobat, sometimes I have to copy a file to every computer, or change a service start from "automatic" to "manual".

Whatever it is, I had a method for generating a list of all my computers, then I would edit with Notepad using Edit/Replace. When I started doing that, I thought I was so efficient, but I wasn't, really. I had to start from scratch every time. It was a simple process but a little tedious.

Here's how I would generate a list of all the computers in Finance. The first letter of all machines began with "F". So I use "net" and "find" to filter...

net view | find/i "\\f" >> fin.txt


After years of editing these things, and needing to update old scripts for doing the same thing a year later, it got to be a mess. For one thing, computers come and go, so I had to regenerate the list of computers repeatedly. Why not just have one master list? Maintain that one list. Use "call" to process it.

Unfortunately, this new way requires three scripts, not one, so it seems more complicated, at first, but in constant use, it's actually much easier.
To keep things sorted and easy to see, I name all the first scripts starting with "1_".
The master list is called "2_FinancePC_List.bat", and that doesn't change - that's my master list that is always kept up-to-date whenever I surplus a PC or get new ones online.

I'll use a query for Adobe as an example.

The first script is short and easy to edit. I can copy the first file from another query and then rename it. So I usually only have to edit the name of the query and the name of the report...
(Warning: some lines might be "wrapped".)

:: =======================
:: Edit the "set" values
:: =======================
title Adobe Query
set CmdPath=D:\RemoteCommands\Queries
set CmdFile=3_AdobeQuery.cmd
set RptFile=Adobe_Report.txt

del /q %CmdPath%\%RptFile%
time /T >> %CmdPath%\%RptFile%
call "D:\RemoteCommands\2_FinancePC_List.bat"
time /T >> %CmdPath%\%RptFile%
start notepad.exe %CmdPath%\%RptFile%


For convenience, the report gets launched in Notepad upon completion.

You can see the real query trigger is "call "D:\RemoteCommands\2_FinancePC_List.bat"". Variables are set in the first script, and passed to the second script. So for each new query, I don't need to edit the master list. That much is generic and part of my seperate, on-going inventory process.

Here's a shortened version of the second file to give you the idea...

call %CmdFile% F1118 "Gotta Gno"
call %CmdFile% F1119 "Betty Whine"
call %CmdFile% F1120 "Bob Bobster"


Of course, this list is pretty long, but all lines are similar. Only the computer name and end-user name are different, and those are passed as parameters "%1" and "%2" to to third script.

The last script is the meat-and-potatoes, and it begins with "3_".

:: Avoid the full time-out wait for each PC that is offline...
@ping -n 1 %~1
if errorlevel 1 goto There

:: Adding the "findstr" command strips out the extraneous two lines the REG QUERY command produces...
@echo %~1 %~2 >> %CmdPath%\%RptFile%

dir /s /b "\\%1\c$\Program Files\Adobe\Acrobat.exe" >> %CmdPath%\%RptFile%
dir /s /b "\\%1\c$\Program Files\Adobe\AcroRd32.exe" | findstr /i Reader

reg query "\\%1\HKLM\SOFTWARE\Adobe\Acrobat Reader\5.0\InstallPath" /ve | findstr /i REG_SZ >> %CmdPath%\%RptFile%
reg query "\\%1\HKLM\SOFTWARE\Adobe\Acrobat Reader\6.0\InstallPath" /ve | findstr /i REG_SZ >> %CmdPath%\%RptFile%
reg query "\\%1\HKLM\SOFTWARE\Adobe\Acrobat Reader\7.0\InstallPath" /ve | findstr /i REG_SZ >> %CmdPath%\%RptFile%
reg query "\\%1\HKLM\SOFTWARE\Adobe\Acrobat Reader\8.0\InstallPath" /ve | findstr /i REG_SZ >> %CmdPath%\%RptFile%
reg query "\\%1\HKLM\SOFTWARE\Adobe\Acrobat Reader\9.0\InstallPath" /ve | findstr /i REG_SZ >> %CmdPath%\%RptFile%
reg query \\%1\HKLM\SOFTWARE\Classes\Installer\Products\68AB67CA7DA73301B7449A0100000010 /v ProductName | findstr /i REG_SZ >> %CmdPath%\%RptFile%
goto END

:There
@echo %~1 - offline - %~2 >> %CmdPath%\%RptFile%
goto END

:END


Here is a sample of what the report looks like...

F1118 Gotta Gno
\\F1118\c$\Program Files\Adobe\Acrobat 6.0\Acrobat\Acrobat.exe
F1119 Betty Whine
\\F1119\c$\Program Files\Adobe\Acrobat 8.0\Acrobat\Acrobat.exe
F1120 Bob Bobster
\\F1120\c$\Adobe\Reader 9.0\Reader\AcroRd32.exe
REG_SZ C:\Program Files\Adobe\Reader 9.0\Reader


With this info, I know who is in the most dire need for upgrades. Depending on the schedule of the end-users, I can conveniently work the upgrades in.

Monday, November 23, 2009

Free Hard Drive Space

Here's a routine that checks a hard drive for free space.
If there's less than about 1GB, turn the window red and report.

@echo.
@echo Checking disk space...
@echo.
@FOR /f "tokens=3 delims=/ " %%G IN ('dir c:^| findstr free') DO (set FreeSpace=%%G)
@FOR /f "tokens=1,2,3,4 delims=," %%i IN ("%FreeSpace%") DO (set FreeVar1=%%i& set FreeVar2=%%j& set FreeVar3=%%k& set FreeVar4=%%l)
@set x=%FreeVar1%%FreeVar2%%FreeVar3%%FreeVar4%
:: Convert bytes to megabytes...
@set /A x/=1048576
@echo.
@If %x% LSS 1000 echo Drive C: only has %x%MB left!& color cf& @echo.& @pause

Above +2,147,483,647, script math fails to be accurate.
2,147,483,647 converted to gigabytes is 1.9999GB, but because it rounds down, it rounds to 1GB.
Since this script is looking for sizes below 1GB, and it's silent above that, it will produce accurate reports.

Saturday, November 14, 2009

Scripts are Super-Lists

Techs do lots of tasks repeatedly. Some lists get very long, like ones for building a computer and all the settings you want to change from the defaults. It's a good idea, when there are tons of things to remember, to make a checklist. This way you guarantee that every computer is built the same.

In the beginning, building a computer in my company (they didn't use Group Policy, nor Roaming profiles) took me a few days (end-users were spoiled and could download and install anything from the Internet, and I was required to migrate all their "toys" and settings).
My job was absolutely overwhelming. Everyone who had my job before me quit - all of them. Too many rude, over-demanding end-users, and my boss backed them, not me.
I soon started scripting. I had scripts for this task, scripts for that task, etc. There were so many scripts for so many things. My build-times got down to a day-and-a-half. This is still a long time, in tech-speak, but I was getting things under control.

Most companies don't allow end-users to play on their computers, and they use Group Policy and Roaming profiles. Building a computer consists of dumping an image to the hard drive and delivering. It's all cookie-cutter - no headaches for techs. If end-users want to play, they should bring a deck of cards.

I got very efficient, I thought. The stress subsided to where it was almost tolerable. My boss saw this, and then dumped an additional department of end-users onto my plate. Back to the impossible hi-stress mode. People with emergencies had to wait up to three days, if I had multiple emergencies going on simultaneously.

That's when it dawned on me that my scripting needed to go to the next level. My collection of scripts needed to be streamlined. To do this, my scripts had to use checks. If "this", then do "this", else do "that". Three scripts became one here, two other scripts became one, etc, but I kept thinking up new tasks that could be scripted. There was one that I ran more often, though. It was my "main" script.

Today, that script is nearly 1200 lines (including blank lines and comments) and is so comprehensive that it will check Adobe versions, Flash, Sun Java, IE version, Office service pack level, check for hard drive errors, etc, etc, etc. And it will even ask if I want to install or upgrade and will call that task. If a computer is new without updates, it will take over an hour to run this script, depending on the installs needed. If a computer is fully up-to-date, this script takes seconds to run, skipping sections that don't apply.
This script allows me to do several hours worth of work in a very short time. And because scripts don't forget, like my busy and aging mind does, nothing gets neglected.
Now it can take me as little as 30 minutes to build a computer and migrate all the user's stuff from the old PC to the new one, right down to the Desktop icon positions on the screen. Other than the end-user's unique data and settings, eveyr computer in my area ends up the same.

Another thing my super-script does is, when I find a problem - or potential problem - I can add certain tweaks to this script. This is proactive and keeps machines healthy.

My stress levels have dropped significantly because I can do an impossible workload using scripts. The workload is no longer impossible.

My company is slowly locking-down what end-users are allowed to do, they've started using Group Policy, Windows Updates are automatic, and they're discussing Roaming profiles. That will help, but I've learned under stress how to get every tiny detail "just right", so my maintenance-and-update script will never be obsolete. It just gets more refined as the years go by.

Eventually, I would like this script to end up being programmed in Visual Basic as an interface tool, calling xml files where options are stored, and allowed any tech to customize what happens, including calling scripts of their own.

Friday, November 13, 2009

32GB eSATA Thumbdrives

Many months ago, I bought a 32GB OCZ Throttle drive. It was awesome!

I like to use the Ultimate Boot CD for Windows (UBCD4Win). I've been using this on USB mostly for Ghosting and anti-virus scanning. Booting off USB is usually fast. (For some odd reason, booting of USB is sometimes slower than booting off a CDROM.)
The bad news about the UBCD4Win is that it boots off an ISO image, which is old technology and limited to 512MB. My collection of stuff is larger than 512MB, but I discovered that I can store the rest of my stuff outside the ISO and it is perfectly accessible as a separate drive after booting off my half-gig ISO. So it's easy to drop anti-virus updates onto it at any time with no hassles.
I was actually one of the geeks who worked on Bart's PE when booting off USB was impossible. I was damn nearly the first person to boot off USB back when the largest drive was 128MB, but the computer I was using was purported to be capable of booting off USB, but wasn't. Someone else beat me to it. Two weeks later, with a Dell D800, my 128MB stick booted up, but I would have had it by a week.
Today, think how fast you could boot the UBCD4Win off an eSATA drive! Vroom!

But I digress...
My OCZ worked for about 2 weeks. Then the eSATA stopped working. This was a surprise. OCZ is very good quality, but this one died. In fact, I suspect it blows every eSATA port it gets plugged into. I have a brand-new Windows 7 supercomputer, and the eSATA doesn't work. I suspect my OCZ blew it. We got a small handful of computers at work that each had eSATA ports, and my OCZ doesn't work on any of them. I suspect I blew them also by plugging my bad OCZ into them. Bummer!

Now I've bought a Kanguru 32GB eFlash. I can't get the eSATA to work, right out of the box, but like I said, I suspect my OCZ blows every eSATA port it gets plugged into, so my supercomputer at home might be bad. I've checked the BIOS and there are NO SATA settings!! Apparently everything is completely automatic when it comes to IDE and SATA on this ASUS motherboard.
So now I wonder - did I blow my new eSATA thumbdrive? Or is it just not initializing because the port is dead?

On to other things...
The USB end works on both drives, so they aren't useless.
The Kanguru partition was garbage. When I right-clicked to create a text file (just for testing), it wouldn't let me. So I created a blank text file on my computer and copied it to the Kanguru. That worked. Then I opened the text file and typed "test" and tried to save, but it wouldn't let me. Weird. It's not read-only, because I just copied this text file to the drive, but I can't create a new text file via right-click, and I can't save from within Notepad.
So I repartitioned and reformatted. Now it works fine - except for eSATA.

But eSATA is probably a waste, with USB3 on the horizon.

Friday, November 6, 2009

PowerShell beginner

I'm just now beginning to learn PowerShell. It's been confusing because too much of the material doesn't tell the details. They shove snippets at you without telling you, "This only works with Windows 7, not in XP", or "This won't work with the default, restricted settings for PowerShell security."
A PowerShell script file ends with the .ps1 extension.

I developed a method to run scripts without permanently lowering my computer's security. You launch scripts from an old-fashioned batch script. The script calls PowerShell, commands security to be lowered just enough to execute the script(s), then raises it back up again. I would also end the .ps1 script by raising the security, in case there's ever a problem returning to the initial batch script.

Try this...
LaunchPSScript.cmd

powershell -command "& {Set-ExecutionPolicy Unrestricted -force}"
@set /p ScriptName=What's the name of your Power Shell script? :
powershell -command .\%ScriptName%
@pause
:: Return the security policy to default, restricted.
powershell -command "& {Set-ExecutionPolicy Restricted -force}"

Run this batch file from the same folder where the PowerShell script resides.
Copy the full name of your script and when prompted, paste the name and hit Enter.

Here's a simple PowerShell script you can use to test this out...
EventLogQry.ps1

clear-Host
# PowerShell script to find Error messages in the System eventlog.
get-EventLog system -newest 2000 | where {$_.entryType -match "Error"}

# Return the security policy to default, restricted.
Set-ExecutionPolicy Restricted -force


With default PowerShell security restrictions, calling the PowerShell script by itself will produce an error like the following...
File EventLogQry.ps1 cannot be loaded because the execution of scripts is disabled on this system. Please see "get-help about_signing" for more details.
At line:0 char:0

Unfortunately, this doesn't work on Windows 7, only on Windows XP.
First, you have to right-click the batch script and "Run as administrator. Okay - no problem.
Second, what breaks it is that the script doesn't run from the path where the script resides. In XP, if you store and run the file from C:\Scripts\PowerShell>, it runs from that path. Not so for Win7. Win7 doesn't care where you run it from, it defaults to C:\Windows\System32>. If I have to hard-code the path, it ruins the convenience of this system.
Third, the command to lower security, or to raise security is squirrelly because I have no permissions on HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell. The weird thing is that the Set-ExecutionPolicy command won't work on my Win7 machine from the PowerShell console, nor from a .ps1 script, but it will work from a batch script. This seems to be a gaping hole in Microsoft's grand scheme, but if it's consistent across Win7 versions and default settings, I'll use it.

I don't mind learning new ways to support Windows 7, but I hope there IS a way to support Windows 7. That was the problem with Vista - unsupportable in a corporate environment. To protect the computer from malicious scripts, Microsoft has set roadblocks just about everywhere. Many things just won't work without a GUI (Graphical User Interface) interruption. I'm really struggling to figure out how to support Windows 7 without lowering security permanently. If there's a way to leave all settings at default, and still operate, that's preferable.