-
« Home
Pages
-
Categories
- Categories
-
Archives
- August 2015
- July 2015
- February 2015
- January 2015
- June 2014
- May 2014
- January 2014
- December 2013
- October 2013
- September 2013
- August 2013
- July 2013
- June 2013
- May 2013
- April 2013
- March 2013
- February 2013
- January 2013
- November 2012
- October 2012
- September 2012
- August 2012
- July 2012
- June 2012
- May 2012
- April 2012
- March 2012
- February 2012
- January 2012
- December 2011
- November 2011
- October 2011
- September 2011
- August 2011
- July 2011
- June 2011
- May 2011
- April 2011
Category Archives: General Discussion
Little feet, marked for measurements, and a smiley face. Round one of my little girls corrective equipment collection begins.
Is addictive…. link
But seriously, the game is absolutely a blast. RPG meets Tower Defense meets Hack and Slash… I’d write more, but I’m going to go back and play.
So I hit up a friend of mine at work to write a quick write up and example of batch scripting; which he leverages heavily administratively, and here’s the result:
For me, batch is the quickest and easiest way to automate most tasks for server administration. These tasks can be completed by leveraging built-in commands, resource kit executables, and other Microsoft/SysInternals type tools. I would like to begin at the beginning, but if I had that much patience I would have learned a real scripting language, so I will start in the middle.
Step 1 is figuring out how to get information you need to manipulate out of the command line, here’s a good start:
http://technet.microsoft.com/en-us/library/cc778084(v=ws.10)
http://www.microsoft.com/en-us/download/details.aspx?id=17657
http://technet.microsoft.com/en-us/sysinternals/bb842062.aspx
Step 2 is formatting and passing that information to additional tools and/or parsing the results for review, (done by the batch itself).
Scenario: You have a directory on a server containing many user profiles. Under these profile directories is a ‘cache’ directory that you want to erase every night. User profiles are create/deleted on a regular basis, so creating a static batch of RMDIR commands is not an option.
C:\Users>dir
Volume in drive C has no label.
Volume Serial Number is B043-A733Directory of C:\Users
07/03/2012 07:20 AM <DIR> .
07/03/2012 07:20 AM <DIR> ..
07/03/2012 07:17 AM <DIR> Andy
07/03/2012 07:17 AM <DIR> Curtis
07/03/2012 07:17 AM <DIR> Daniel
07/03/2012 07:17 AM <DIR> Mark
You want to run the command: rmdir /s /q c:\users\<insert username>\cache, where the username is dynamically pulled from the current c:\users directory. First, tweak your command with any available options/flags that give you an output that is easier to work with. In this case, the /b (brief) flag for DIR will strip the output of any extra format.
C:\>dir c:\users /b
Andy
Curtis
Daniel
Mark
We will reference the output from this command as a single string variable per line, so removing header formatting and unnecessary columns is ideal. For this script I’ll be using a FOR loop; there are several different types of FOR loops in DOS, though I use /F (filenameset) almost exclusively. Typing FOR /? from a command prompt will give you the full list of options, but we will focus on the two that read from either a text file or a command output. From the FOR /? help:
FOR /F [“options”] %variable IN (file-set) DO command [command-parameters]
FOR /F [“options”] %variable IN (‘command’) DO command [command-parameters]
The “options” I most commonly use are “tokens” and “delims”, to specify which column(s) to read from, and what character(s) delimit columns (blank space is the default delimiter). We narrowed down the output to only one column, so “delims” will not be used in this example, and there is only one token available.
@echo off for /f “tokens=1” %%a in (‘dir c:\users /b’) do (rmdir /s /q c:\users\%%a\cache)
Lets take a closer look at each component of the for loop and what it is doing:
for /f
Perform an action for every line in a text output
“tokens=1”
Identify the first word on every line (tokens=2 would be the second word, etc)
%%a
Reference that first word of every line as %%a
in (‘dir c:\users /b’)
The text output we are reading from is the command ‘dir c:\users /b’
you can also read a text file instead of command output by removing the single quotes,
IE: for /f “tokens=1” %%a in (serverlist.txt)
do (actions)
action(s) to be performed for every line
Now this batch is ready to be added as a scheduled task and automatically delete the specified cache directories every night. You can create the scheduled task via command line as well, but I don’t see much of a need for that in this case. As much as I enjoy automation and CLI, I typically avoid both when they are not the quickest way to get the job done.
I know quite a few people who wouldn’t want this robot at their dinner table….
A father buys a lie detecting robot that slaps a person when he lies. The father decides to test it out on his son at supper.
“Where were you last night?”
“I was at the library.”
The robot slaps the son.
“Okay…I was at a friend’s house.”
“Doing what?” asks the father.
“Watching a movie; ‘Toy Story.'”
The robot slaps the son.
“Okay…it was porn!” cries the son.
The father yells, “What? When I was your age, I didn’t know what porn was!”
The robot slaps the father.
The mother laughs and says, “He certainly is your son!”
The robot slaps the mother.
bazziiing!
Alright, so if you read my previous post for AD to DB then this post will make more sense. However if you haven’t; then now would be a good time to… go ahead, I’ll wait.
Now one of the primary purposes I had for this data was to leverage it against my v_r_system view and determine which active assets are missing their client. Well that’s fine and good, but I had been in the habit of taking that data and then performing a DNS check for the entries using a Powershell script written by Jason Sandys. Originally I was using a vbscript I wrote to do so, but found his to be far more efficient since it made use for the DNS class in .Net. But I digress, the end result is that I had quite a few additional steps to determine which machines were active, and ready for remediation either locally by desktop support, or by my remote repair tools.
So, what to do? Why not query what I need, run the DNS check from a data set, then write the results back to my data warehouse? This script requires a few things:
- Working, integrated credential for querying the SCCM DB; and permission to drop, insert, and create for the DB warehouse.
- Table within the data warehouse with the AD data provided with my AD to DB script to join against the SCCM DB data.
- Established linked servers between the two databases to perform the join (stored query in the script calls the join from the SCCM DB server, so the link is required there)
Now that we have that out of the way lets discuss the variables that need to be modified here.
- $db – SCCM Database for the primary site server
- $sqlsrvr – SCCM Database Server Name
- $db2 – Data Warehouse DB
- $sqlsrvr2 – Data Warehouse Server Name
- $table – Data Warehouse AD Table
Alright, so there it is, now time for the code; which I want to apologize in advance for it’s wide column width (download):
#We expect errors for hosts we can't find, so running silently $ErrorActionPreference = "SilentlyContinue" #Configuring connection and query variables for the sql client adapter $db = "sms_abc" #sccm database $sqlsrvr = "SCCMDBServer" #sccm db Server Name $db2 = "DataWarehouse" #Data Warehouse db $sqlsrvr2 = "DataWarehouseServer" #Data Warehouse Server Name $table = "ADtablefromDatawarehouse" #The table where AD data is stored $sqlquery = "select sys.Name0 from $sqlsrvr.$db.dbo.v_r_system as sys join ` $sqlsrvr2.$db2.dbo.$table as adlist on adlist.ad_machine = sys.name0` where DATEDIFF(d,passwordlastset,getdate()) <= 30 and Client0 = 0 or` DATEDIFF(d,passwordlastset,getdate()) <= 30 and Client0 is null" #Performing the query and writing to a data set $sqlcon = New-Object System.Data.SqlClient.SqlConnection("Data Source=$sqlsrvr;Integrated Security=SSPI;Initial Catalog=$db;") $cmd = New-Object System.Data.SqlClient.SqlCommand $cmd.CommandText = $SQLQUERY $cmd.Connection = $SQLCON $sqladapter = New-Object System.Data.SqlClient.SqlDataAdapter $sqladapter.SelectCommand = $CMD $DS = New-Object System.Data.DataSet; $DS.Tables.Add("SQLQuery") [Void]$sqladapter.Fill($DS.Tables["SQLQuery"]) $sqlcon.Close() #Building new table in SQL for DNSQuery $table = "NoClientDNSRecord" $sqlcon = New-Object System.Data.SqlClient.SqlConnection("Data Source=$sqlsrvr2;Integrated Security=SSPI;Initial Catalog=$db2;") $sqlcon.Open() $cmd = $sqlcon.CreateCommand() $cmd.CommandText = "drop table $table" [Void]$cmd.ExecuteNonQuery() $cmd.CommandText = "create table $table (Name varchar(150) not null Primary key,IP varchar(25), Reverse varchar(150), status varchar(50))" [Void]$cmd.ExecuteNonQuery() #Performing a DNS query against each machine in our SQL data set foreach($row in $DS.Tables["SQLQuery"].rows){ $system = $row[0] $sys = New-Object PSObject $sysname = $system.ToLower().Trim() $sys | Add-Member -MemberType NoteProperty -Name Name -Value $sysname #Getting IP address for the host name $sys | Add-Member -MemberType NoteProperty -Name IP -Value "-" $sys.IP = [System.Net.DNS]::GetHostEntry($sysname).AddressList | select -First 1 $firstOctet = ($sys.IP -split "[.]")[0].Trim() #Getting reverse address from dns for the host name $sys | Add-Member -MemberType NoteProperty -Name Reverse -Value "-" $sys.Reverse = [System.Net.DNS]::GetHostEntry($sys.IP).HostName | select -First 1 $sys.Reverse = ($sys.Reverse -split "[.]")[0].ToLower().Trim() if ($sys.Reverse -eq $firstOctet){$sys.Reverse = "-"} #Writing a status for the entry based on name and reverse lookups. $sys | Add-Member -MemberType NoteProperty -Name Status -Value "-" if ($sys.IP -eq "-") ` {$sys.Status = "Could not Resolve IP"} elseif ($sys.Reverse -eq "-") ` {$sys.Status = "IP Address not found in reverse zone"} elseif ($sys.Name -ne $sys.Reverse)` {$sys.Status = "IP registered to another system"} else ` {$sys.Status = "OK"} #Writing values to SQL $cmd.CommandText = "insert $table values ('$($sys.name)','$($sys.ip)','$($sys.reverse)','$($sys.status)')"; [Void]$cmd.ExecuteNonQuery()} $sqlcon.close()
I’d recommend using PowerGUI for reviewing/modifying this code as it’s by far the best (free) powershell editor available.
Until next time, have a good one!
Nothing serious here, but I just can’t stop laughing at this RPG Motivational poster….
D&D Rogues get it…
So I had another problem, and one I know I’m not alone in…
I’ve got clients that are failing, won’t install, have corrupt wmi repositories, and obviously I can’t deploy a repair solution to them so what do we do?
Well like most people in an enterprise environment (or smaller I’m sure) we maintain a logon script, and considering that this script will run come hail or high water it is clearly the best possible automated resolution point possible.
There have been some really great log on health check scripts written by a lot of great people in the MyITForum community, and having used two of the more popular ones I’ve decided there are some great things in both of them, but in one case more than what I need; and the other just short of my needs.
So what do we do? Simple, write our own; which you can download from a link at the bottom of this post.
So lets first look at what it takes to run this script:
CmLogonFrameWork.wsf + config.xml
At run time you can configure 4 override settings:
- /log:”c:\windows”
This will write the logfile to the windows directory.
- /config:”somefilesomewhere.xml”
This will load the specific config file you need, useful if you have multiple configurations for multiple machine/user types.
- /events
This will force the script to write events to the event log regardless of how it’s defined in the config.xml
- /debug
This will force the script to error verbosely, which will become useful if you are going to extend the code and need to see the error output.
So what does the script do? Well I’ve put my horrible Visio skills to work to give you the obfuscated flowchart that might very well make you want to claw your face off (included in the script download). However I’ll give you a quick overview of the intended functionality to save you from all the head scratching and the “what was this guy smoking” statements you might have as you read it.
It’s best to think about this script in 5 blocks:
- Initialization
- System Check
- SCCM Check
- SCCM Configuration
- Close Out
Initialization:
This block is fairly straight forward. We gather arguments, enforce a cscript execution (for cleanliness more than anything), generate our first log entry, load the configuration file, and write a LastRun entry to HKLM\Software\SccmHealth for tracking of changes and repair mechanisms later.
The only potential repair function during this phase would be to the XMLDom (and all the script will attempt to do is register the component). If OS version checks fail, or the XML file cannot be read then the script will close with an error in the log.
System Check:
The system check is also fairly straight forward. We first check the admin account if one is configured, we check the admin shares, we check the list of services defined in the config, and finally we verify that the root/cimv2 is accessible in WMI.
Repairs that would occur in this phase are the enabling of admin shares via service and registry values. Services are configured per the config file if they are not presently in that state. And finally if it’s enabled, an attempted wmi rebuild would be performed if wmi fails its check (there are two distinct repair types determined by the version of windows).
SCCM Check:
Now things get a bit more confusing, but I’ll keep it high level since I have a bit of an election system in the script on what repair method is the best option.
Check the CM namespace in WMI, then the service, then the executable, and finally the setup files. If all 4 fail or 3 of 4 then a standard installation will occur. If only the namespace fails then a reinstallation is attempted provided that option is allowed, if not then a wmi repair is attempted if it is allowed. There are other checks that manipulate the outcome such as your configuration options obviously and when the last repair date was attempted on the asset.
SCCM Configuration:
This section is very straightforward.
Check the Site code, and check the cache size, if they don’t match the config, we change them to match.
Close Out:
As our final phase we load any additional scripts identified in the config file, generate our System Check, SCCM Check, and SCCM Configuration check report card. If remote logging is enabled we write the final output there as well, and finally we deconstruct our objects and terminate the script with or without errors depending on the outcome of course.
Tips for Extending:
The two custom objects being used here in this script are cls_Logging and cls_Dict which are instantiated as Logging and Config respectively.
A list of these classes and how they work can be found here (logging) and here (config).
I’ve also included a test.vbs that extends the script to give you an idea of some of very basic examples of extended functionality. I would recommend you avoid adding anything to the primary script, but instead extend it all as a separate script and have it performed at the end of the script, unless of course it’s an entirely new object that you wish to build into this tool then by all means have at it.
If you have any questions, suggestions, or if you find bugs please comment so I can answer them or repair them, thanks.
Download:
Although I don’t agree with the language used here to emphasize the point, I can’t help but agree with the underlying message here. I would wish that everyone would live a life free of substance abuse, but I do not believe the harsh penalties inflicted upon those who partake is either fair or effective. I do not believe that the hypocrisy inherent in the system is funny; and I most CERTAINLY do not agree in the involvement of federal government in the affairs of the state.