So I’m watching Mace Windu in action, then something occurred to me.
Anyway, I laughed pretty hard at this realization.
Mind = blown
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.
A simple vbscript I use for manual client installation. It does some basic quick checks and fixes before begining an install. One could feasibly use this for health checking, but it’s not nearly as robust as my actual logon framework or other scripts from people like Jason Sandys or Dan Thompson.
The variables strAdmin (local admin service account), strCcmSetup (path to folder with the ccmsetup.exe), and strArguement (install string) need to be defined before running the script. It’s worth mentioning that strCcmSetup is just the path to ccmsetup.exe, there is no need to actually type ccmsetup.exe into the path and it’s best if you don’t since I didn’t bother writing anything in to verify if it is or isn’t. The script will auto append the executable to that variable so ccmsetup.exe in the path will give you ccmsetup.execcmsetup.exe
'Author Daniel Belcher || 'CCMsetup Function || 'Date 2/11/2011 rev 5/20/2011 || '==================================|| '|Objects, Variables, and Constants ******************************************** '=============================================================================|| '|| Non-Standard Installer Variables - Please define them || '|| Admin Account strAdmin = "domain\user" '|| Path to ccmsetup.exe strCcmSetup = "\\path\where\ccmsetup.exe\resides\" '|| Install string strArguement = "/noservice SMSSITECODE=ABC SMSSLP=SERVER.ADDRESS " _ & "SMSFSP=SERVER.ADDRESS" ' || '=============================================================================|| Const DEBUGMSG = False 'Boolean to use for testing False = Silent True = Verbose Const ForAppending = 8 Dim oWShell Set oWShell = CreateObject("WScript.Shell") Dim oFSo Set oFSO = CreateObject("Scripting.FileSystemObject") Dim oNet Set oNet = CreateObject("Wscript.Network") ComputerName = oNet.ComputerName Dim Target Target = "." Dim oWMISvc Set oWMISvc = GetObject("winmgmts:\\"&Target) '|Main Run *******************************************************************|| '=============================================================================|| WriteLog "Starting "&Wscript.Scriptname&" on "&ComputerName,2 PreReq CCMSetup Report 'SubRoutines *****************************************************************|| '=============================================================================|| Sub WriteLog(msg,mtype) 'Subroutine for writing the log logname = wscript.scriptname&".log" if not oFSo.FileExists(logname) then oFSo.CreateTextFile(logname) end if msgline = "<![LOG["&msg&"]LOG]!><time="&""""&DatePart("h",Time) msgline = msgline &":"&DatePart("n",Time)&":"&DatePart("s",Time) msgline = msgline &".000+0"""&" date="""&Replace(Date,"/","-") msgline = msgline &""""&" component="""&WScript.ScriptName msgline = msgline &""" context="""" type="""&mtype msgline = msgline &""" thread="""" file="""&WScript.ScriptName& """>" Set oLogFile = oFSo.OpenTextFile(logname, ForAppending, True) oLogFile.WriteLine msgline oLogFile.Close if DEBUGMSG then wscript.echo msg&" "& mtype End Sub '******************************************************************************* Sub SvcStart(service) 'Attempts to start a service Set WMIServices = oWMISvc.ExecQuery _ ("Select * from Win32_Service where name = '"&service&"'") For Each item in WMIServices if lcase(item.startmode) <> "automatic" then item.ChangeStartMode("Automatic") end if start = item.startservice() wscript.sleep 4000 if start <> 0 Then WriteLog "ERROR: Failed to start the "&service&" Service, " _ & "investigation required", 3 wscript.quit(0) else WriteLog "Succesfully started "& service &" Service",1 end if next End Sub '|Functions ******************************************************************|| '=============================================================================|| Function PreReq 'Prerequisite check for client installation Set WMIServices = oWMISvc.ExecQuery _ ("Select * from Win32_Service") strService = "lanmanworkstation" regAdminSPath = "HKLM\SYSTEM\CurrentControlSet\services\LanmanServer\" _ & "Parameters\" For Each item in WMIServices if lcase(item.name) = strService then if lcase(item.state) <> "running" then writelog "Warning: "&strService&" was not running, " _ & "attempting to start...", 2 SvcStart strService else writelog strService& " was found running, OK", 1 end if end if next if not oFSO.FolderExists("\\"&computername&"\admin$") then WriteLog "Warning: Admin shares not available, attempting to add " _ & "registry key...", 2 On Error Resume Next oWShell.RegWrite regAdminSPath & "AutoShareWKS", 1, "REG_SZ" if err.Number <> 0 then WriteLog "ERROR: "®AdminSPath&"AutoShareWKS, 1 failed to write, or " _ &"already exists.", 3 else WriteLog regAdminSPath&"Notice: AutoShareWKS, 1 written succesfully. " _ & " Restart required to take effect.", 2 end if Wscript.Echo "AutoShareWKS key was written to: " &vbcrlf _ ®AdminSPath & vbcrlf _ &"Please restart the machine, and rerun this script" else WriteLog "Admin$ shares found, and working.", 1 end if Set AdminCheck = GetObject("WinNT://" & oNet.ComputerName _ & "/Administrators,group") if AdminCheck.IsMember("WinNT://"& strAdmin) then WriteLog "User "&strAdmin&" found in Local Adminstrators group", 1 else WriteLog "Warning: User "&strAdmin&" not found in Local Administrators group",2 on Error Resume Next AdminCheck.Add("WinNT://"&strAdmin) if Err.Number <> 0 then WriteLog "ERROR: Unable to add "&strAdmin&" to the Local Administrators group",3 Wscript.Echo "Unable to add "&strAdmin&" to local Admins." & vbcrlf _ &"Please do so manually and rerun this script." Wscript.Quit(0) end if end if End Function '******************************************************************************* Function CCMSetup 'Client detection and installation Set WMIServices = oWMIsvc.ExecQuery _ ("Select * from Win32_Service where name ='ccmexec'") boorun = true for each objservice in WMIServices strservice = lcase(objservice.name) if strservice = "ccmexec" then boorun = "False" next if not boorun then For Each service in WMIServices if lcase(service.state) <> "running" then svcStart "ccmexec" 'Attempt to start service if stopped WriteLog "Warning: CcmExec service found, but was not running, " _ & "attempting to start...", 2 end if next WriteLog "SCCM client service, CcmExec found, closing script", 1 exit function end if if boorun then oWShell.run strCcmsetup&"ccmsetup.exe " & strArguement WriteLog "CcmSetup has begun using: ccmsetup.exe"& strArguement,1 end if End Function '****************************************************************************** Function Report If DEBUGMSG then msgbox "Complete" 'Set for popup on script complete End Function 'End *************************************************************************|| '=============================================================================||
As has become my standard, the logs are written in a markup that works with trace32.
Ok, so I’ve not posted anything for a few days and I felt the need to throw a brief technical post up with a code snippet from a current project I’m working on. I’m building a health check logon script and as part of that framework I wanted to build a logging object. Since the target format has to be vbscript for what I’m doing, I’ve built it as such, and in a format that views nicely inside of trace32 and trace64.
The idea was to build an object that would perform a simple task, write a log file…. then write a log file, or an event, then write only error events, but could also buffer and dump a final error or success log as a split log to another remote location. All configurable via properties, but with only two exposed methods to control it all (write & writeremote). This object is instantiated by:
Dim Logging Set Logging = New cls_Logging Call Logging.Write("my message",1) Wscript.Quit(0)
Simple enough, no? It’s also worth mentioning I wrote the code so that a constant could be set within the instantiating script of DEBUGMODE and if TRUE it will error, else suppresses all error output.
'================================================================================= 'Logging Class =================================================================== '================================================================================= 'Not required for WSF, but is when in standard VBS Const ForAppending = 8 'Log and Event writer object Class cls_Logging 'Class for logging to file and event viewer Private oWShell,oNet,oFSo,Filehandle,rFilehandle Private fPath,strRFPath,fMaxSize,fLogname,strRemoteErr,BoolEvent,BoolRemote,oDict Private Sub Class_Initialize() 'Object Init subroutine If Debugmode Then On Error Goto 0 Else On Error Resume Next Set oWShell = CreateObject("Wscript.Shell") Set oNet = CreateObject("Wscript.Network") Set oFSo = CreateObject("Scripting.FileSystemObject") Set oDict = CreateObject("Scripting.Dictionary") LogEvent = False RemoteLog = False Path = Left(WScript.ScriptFullName,(Len(WScript.ScriptFullName)_ -Len(WScript.ScriptName))) File = LCase(oNet.ComputerName) MaxSize = 2 End Sub '--------------------------------------------------------- Private Sub Class_Terminate() 'Object Termination subroutine If Debugmode Then On Error Goto 0 Else On Error Resume Next If bOpen Then Filehandle.close End If Set oWShell = Nothing Set oNet = Nothing Set oFSo = Nothing Set Filehandle = Nothing Set fPath = Nothing Set fMaxSize = Nothing Set fLogname = Nothing Set BoolEvent = Nothing End Sub '--------------------------------------------------------- 'File name properties, for changing and retrieving the log file name Public Property Let File(strFile) If Debugmode Then On Error Goto 0 Else On Error Resume Next If (InStr(StrReverse(strFile),"gol.")) <> 0 Then fLogname = strFile Else fLogname = strFile & ".log" End If End Property Public Property Get File() If Debugmode Then On Error Goto 0 Else On Error Resume Next File = fLogname End Property '--------------------------------------------------------- 'Path name properties, for changing and retrieving the path to logs Public Property Let Path(strPath) If Debugmode Then On Error Goto 0 Else On Error Resume Next If (InStr(StrReverse(strpath),"\")) <> 1 Then fPath = strPath & "\" Else fPath = strPath End If End Property Public Property Get Path() If Debugmode Then On Error Goto 0 Else On Error Resume Next Path = fPath End Property '--------------------------------------------------------- 'Fully concatenated file name property for retrival. Public Property Get FullFileName() FullFileName = Path & File End Property '--------------------------------------------------------- 'Property for setting maximum file size of log file Public Property Let MaxSize(strVal) If Debugmode Then On Error Goto 0 Else On Error Resume Next fMaxSize = Cint(strVal) * 1048576 End Property Public Property Get MaxSize() If Debugmode Then On Error Goto 0 Else On Error Resume Next MaxSize = fMaxSize End Property '--------------------------------------------------------- 'Boolean property to determine if the filehandle is in use Private Property Get bOpen() If Debugmode Then On Error Goto 0 Else On Error Resume Next If IsObject(Filehandle) Then bOpen = True Else bOpen = False End If End Property '--------------------------------------------------------- Public Property Let LogEvent( blValue) 'Bool property that dictates event viewer rights BoolEvent = blValue End Property Private Property Get LogEvent() LogEvent = BoolEvent End Property Public Property Let RemoteLog( blValue) 'Bool property that dictates if logging occurs to remote location BoolRemote = blValue End Property Private Property Get RemoteLog() RemoteLog = BoolRemote End Property Public Property Let RemotePath( strPath) If (InStr(StrReverse(strpath),"\")) <> 1 Then strRFPath = strPath & "\" Else strRFPath = strPath End If End Property Public Property Get RemotePath() RemotePath = strRFPath End Property '--------------------------------------------------------- Private Sub RemoteErrBuffer( strKey, strItem) 'Method to concactenate new items under one key at the end of the string If Debugmode Then On Error Goto 0 Else On Error Resume Next Dim concat If Not oDict.Exists(strKey) Then Call oDict.Add(strkey, stritem) Else concat = oDict.Item(strKey) concat = concat & "|:|" & strItem oDict.Remove(strKey) Call oDict.Add(strKey,concat) End If End Sub '--------------------------------------------------------- Public Function ErrBuffer() 'Method to return contents of the error buffer If Debugmode Then On Error Goto 0 Else On Error Resume Next Dim ItemToSplit, ItemArray, item ItemToSplit = oDict.item("remotelog") ItemArray = Split(ItemToSplit, "|:|") ErrBuffer = ItemArray End Function '--------------------------------------------------------- Public Sub WriteRemote(strVal) If Debugmode Then On Error Goto 0 Else On Error Resume Next If Not CreateRemote Then Exit Sub End If rFilehandle.WriteLine strVal End Sub '--------------------------------------------------------- 'Subroutine for creating the remote log file and instantiating the handle Private Function CreateRemote() If Debugmode Then On Error Goto 0 Else On Error Resume Next Dim FileProperty,Logsize CreateRemote = False If Not oFso.FolderExists(RemotePath) Then Call Write(RemotePath & " Does not exist, or is unreachable.",3) Exit Function End If If Not oFSo.FileExists(RemotePath & File) Then oFso.CreateTextFile(RemotePath & File) Else oFSo.DeleteFile(RemotePath & File) oFso.CreateTextFile(RemotePath & File) End If If Not IsObject(rFilehandle) Then Set rFileHandle = oFSo.OpenTextFile(RemotePath & File, _ ForAppending, True) End If If oFSo.FolderExists(RemotePath) Then CreateRemote = True End If End Function '--------------------------------------------------------- 'Subroutine for writing log entries Public Function Write( msg, mtype) If Debugmode Then On Error Goto 0 Else On Error Resume Next Dim msgline, etype Call Create() If Not bOpen Then Call Create() End If msgline = "<![LOG["&msg&"]LOG]!><time="&""""&DatePart("h",Time) _ &":"&DatePart("n",Time)&":"&DatePart("s",Time)&".000+0"""&" date=""" _ &Replace(Date,"/","-")&""""&" component="""&Left(WScript.ScriptName, _ Len(WScript.ScriptName)-Len(".vbs"))&""" context="""" type="""&mtype _ &""" thread="""" file="""&Left(WScript.ScriptName,Len(WScript.ScriptName)_ -Len(".vbs"))& """>" Filehandle.WriteLine msgline Select Case Mtype Case 1 etype = 0 Case 2 etype = 2 If LogEvent Then oWShell.LogEvent etype, msg End If Call RemoteErrBuffer("remotelog", msg & "," & "2") Case Else etype = 1 If LogEvent Then oWShell.LogEvent etype, msg End If Call RemoteErrBuffer("remotelog", msg & "," & "1") End Select End Function '--------------------------------------------------------- 'Subroutine for rolling over log file at file size limit Private Sub Rollover() If Debugmode Then On Error Goto 0 Else On Error Resume Next If bOpen Then Filehandle.Close End If oFso.CopyFile FullFileName, Left(FullFileName,(Len(FullFileName)-1)), True oFSo.DeleteFile FullFileName Set FileHandle = oFSo.OpenTextFile(FullFileName, ForAppending, True) End Sub '--------------------------------------------------------- 'Subroutine for creating the log file and instantiating the handle Private Sub Create() If Debugmode Then On Error Goto 0 Else On Error Resume Next Dim FileProperty,Logsize If Not oFSo.FileExists(FullFileName) Then oFSo.CreateTextFile(FullFileName) End If If Not bOpen Then Set FileHandle = oFSo.OpenTextFile(FullFileName, ForAppending, True) End if Set FileProperty = oFSo.GetFile(FullFileName) Logsize = FileProperty.size If Logsize > MaxSize Then Filehandle.WriteLine "\\\\\\\\\\File Size Reached//////////" Call Rollover() End If End Sub End Class
I built a scripting dictionary wrapper as well which was inspired by work from Dan Thomson in his health check script. I’ll most likely post it next after I feel it’s complete.
If you found this object helpful, or otherwise, I would appreciate it if you rated it on script center.
My daughter Maggie, who I’ve mentioned on here before, has some major issues (undiagnosed as of yet) that have caused her considerable developmental delays. This past Sunday was a major breakthrough for her, and my wife has done a fine job of summing it up for those interested in reading it.
I’m not really sure WHAT inspired me to come back and give it a try again…
When it first released and I bought it (being a long time fan of Turbine games) I really enjoyed it. The game offered multiple layers to it’s (at the time only) PvE element for both customization and character development, it had a rich overarching story telling system (similar to the now defunct AC2), and great universe integration. It had about everything I enjoy in an MMO, but for whatever reason, it didn’t grab me. Perhaps it was due to the clunky skill systems, or the over all busy nature of the games complexity, but it just felt wrong after I got past my 20s/30s in the game.
Navigation was a headache, and often times, the little to no reward I started seeing from the quest lines began to leave me wanting more. The amount of work required to do basic things, such as combat, also began to wear on me (I was a loremaster, which is a very inventive great class).
However, several expansions, engines, and a pay model change later I’ve decided to give it a go again; here are my initial impressions upon returning (some of these I’ve experienced from recent jaunts back as well):
- Graphics have improved
- Character responsiveness still not what I’d like to see
- Storylines have become richer
- Customizations have branched further
- PvP is a nice addition, but meh
- Soloing feels easier
- Free to Play model seems implemented fairly well
- Long term game play feels more promising than before
So lets discuss these points a bit more.
DX11 has been integrated, aside from some differences in the shadows, soft particles, and some interactive water effects (not sure why this wasn’t done prior to DX11) I don’t see a huge difference from the previous DX10 and DX9 iteration. Textures (although high res versions have been available for a while) still don’t offer anything new, no tessellation, I don’t suspect or expect them to redo all the in game textures and engine, especially since I already find the game quite beautiful but the tech in me always wants to see rendering boundaries pushed. Mind you I’m on an SLI rig that is DX11 capable, I WANT to make use of that when I game.
Character responsiveness has always been a bit of a nagging point for me in Turbine games since their original Asheron’s Call. I can only assume it’s something to do with their code that requires server response before the client will report movement. Most online games allow the client to dictate to the server it’s position and the server simply analyzes that and agrees or disagrees with the client. This is called client-side prediction and has been in use in multiplayer games since the days of Quake at least. Wikipedia states that Duke Nukem 3D used it as well, but my first real taste of the difference came from shifting out of native Quake DM into QuakeWorld DM where it existed, but I digress. It might even be that Turbine engines USE a form of client-prediction that requires some sort of start receive message before engaging client control, I don’t know, but it causes the client side experience to feel delayed to some extent.
So what does that all mean in a practical scenario? It basically means, when I press forward, either I move forward, or I have to wait a split second or more before my character moves forward. Both can create unfavorable gaming moments, but I feel that the method in place in Turbine games has been problematic since it’s inception, especially given the responsive nature of their game mechanics. The thing of it is, in their current design, you are less likely to be called back to a previous position (rubber banding) but rubber banding generally only happens in the most extreme of latency/packet loss cases. So to avoid rubber banding (I suppose) they verify client input prior to client output, and I see a delay before I can change my X Y or Z position in the game world.
I would be remised though if I didn’t mention it’s game integrity benefits though as well. It protects the server from being deceived by client-side “trainers” or utilities that can report illegal positions used to exploit game mechanics. Anyone who’s played WoW and knows about people porting and speed hacking etc, these are fundamental vulnerabilities to that technical design. Tolerances usually exist in client prediction to allow a client to get from point a to point b without having to report every step across the grid. That tolerance NEEDS to be there or you would see a lot of rubber banding, this is what allows smooth game play on really bad connections. However, it’s easy to exploit that relationship by passing bogus packets to the server. Both require creativity to overcome their hurdles, and they both do so well enough. For me personally I feel with client prediction you open yourself to more administrative headaches in an MMO, but a better customer experience. So I can’t help but feel it’s non-use is a form of laziness at the cost of the gamer. One could reason it improves customer experience by insuring a level playing field but lets just move on.
Storylines, customizations, soloing, and PVP aren’t NEW features per say, but they are features that didn’t exist or have become more robust since it’s release in 2007. They’ve got 2 expansions and a 3rd on the way so there has been and will still be growth in this game. It, like a fine wine, has matured rather nicely. I’ve also been a fan of Turbine’s story telling, and LotRO is no different, and only continues to prove (to me) their mastery in the medium of engaging RPG content in an MMO. They’ve revamped their starting story lines, and added more tie ins to their quest chains, they introduced new methods for questing/instancing/booking called skirmishes as well. I could go on for a long time about all the methods they have taken to make their storylines relevant and effective to meet game play but it’s something one has to experience I think more than read about. The addition of their PvP system (called PvM for Player Versus Monster) even insures story integration into their game by forcing players to spin off new evil characters strictly for PvP.
The other aspect of the game I’ve always found intriguing is their deeds, titles, outfitting, traits, and dying systems. All offer a robust amount of options for character diversity in their own right, but can really offer diverse customizations when the sum of all parts come together. Mind you, like all MMOs, people will MIN/MAX so some of the traits etc become pretty cookie cutter for what is used, but it’s not from a lack of options that’s for sure. They’ve continued to add to these systems, and at times it leaves my head swimming trying to keep track of them all, I tend to be a meta gamer so information overload is definitely something I suffer from when reviewing the possibilities.
The solo aspect of the game also seems to be more realistic than it was at release. Not so much that you can check out when you are playing, but enough that one can keep a decent rate of progression while going at it alone. Also some of the earliest content that was at one time a guaranteed group event has been scaled back. Some may complain it’s TOO easy now, and they may be right, but I feel it’s found a sweet spot.
They’ve also converted to a Free to Play gaming model which seem to be all the rage now with MMOs (Thanks Korea!). For anyone not familiar with a standard F2P gaming model it’s simple, offer a game for free, gut some features out and reserve them for 1) subscribers 2) one time game purchase 3) micro transactions. In a nutshell, like selling crack. The first one’s always free!
But seriously, it’s a clever business model, for a guy like me it gives me a demo of what I’m going to invest in and leaves me the option of giving my monthly sub since I’ve no issue with that (and haven’t since I really started into MMOs back in 97/98). There is also a warm fuzzy seeing an itemized list of things you are getting for your money. Mind you, it’s all nonsense and I am aware of that, but “if I pay monthly I get…” definitely passes through my mind as a comfort statement when I’m looking at F2P games. This one of course being no exception, I’m not a huge fan of micro transactions, I’d rather lease the service than commit to it.
At any rate, it’s flexible, and playable even if you want to go in on the cheap. Kudos to them for making that transition, and congratulations on their success with it.
Overall I feel the long term playability of the game has vastly improved, but it’s definitely got it’s competition like all other games. There appears to be plenty of high end content and customizations to chase after. There’s also multiple facets to their storylines as well that are worth exploring that I think give incredible replay value to their game. I suppose I’ll keep going with this for a while in my free time as my fill in game.
If you are interested, look for me, or mail me in game on either Lotekend or Jahosi.
Ok, why does that matter?
Because reading logs inside PE with notepad is horrible…..
Have a great day!
My wife’s birthday post for me! I’m a very blessed man indeed.