Find out if computer rebooted since the last time my program ran? - windows

How can my program know if windows rebooted since the last time it ran? All versions of windows XP and on.

This can be accomplished trivially using the global atom table. Just make sure your atom name is unlikely to conflict with another atom.
if (GlobalFindAtom ("MySecretName") == 0)
{
// First time run since reboot
GlobalAddAtom ("MySecretName");
}

There's a Windows API call you can make called GetTickCount...
http://msdn.microsoft.com/en-us/library/ms724408%28VS.85%29.aspx
Edit: The idea is that when your program starts, you make a call to GetTickCount (which returns how many milliseconds Windows has been running), and then calculate an exact start date (right now minus the number of milliseconds). Store that date, and then the next time your program starts, calculate the date again and compare it to the previously stored date. If the dates are different, Windows has rebooted. Use GetTickCount64 if possible (but don't code your solution solely using this function.

You can use WMI:
strComputer = "."
Set objWMIService = GetObject _
("winmgmts:\\" & strComputer & "\root\cimv2")
Set colOperatingSystems = objWMIService.ExecQuery _
("Select * from Win32_OperatingSystem")
For Each objOS in colOperatingSystems
dtmBootup = objOS.LastBootUpTime
dtmLastBootupTime = WMIDateStringToDate(dtmBootup)
dtmSystemUptime = DateDiff("h", dtmLastBootUpTime, Now)
Wscript.Echo dtmSystemUptime
Next
Function WMIDateStringToDate(dtmBootup)
WMIDateStringToDate = CDate(Mid(dtmBootup, 5, 2) & "/" & _
Mid(dtmBootup, 7, 2) & "/" & Left(dtmBootup, 4) _
& " " & Mid (dtmBootup, 9, 2) & ":" & _
Mid(dtmBootup, 11, 2) & ":" & Mid(dtmBootup, _
13, 2))
End Function

net statistics workstation|find "Statistics since"

The Microsoft utility uptime.exe "processes the machine's event log to determine system availability and current uptime".

Simple, but ugly solution : just launch a never-ending dummy process :-)
If it's still here, you didn't reboot. If it's not, chances are that you have just rebooted.

In the vein of ugly hacks ... stick something in one of the RunOnce registry keys

How about adding a file to %TMP% and check if it's still there (%TMP% should be cleared at each reboot by Windows)
or
more robust way, create a file somewhere and mark it for deletion on next reboot (see MoveFileEx API) and check that file

Related

Modify NTEventlogFile OverwritePolicy/Retention Cycle by WMI

I‘m trying to set via VBS the Win32_NTEventlogFile to keep entries for 10 days. I know I need an elevated shell to modify the security log. I’ve used the samples from Microsoft with this code
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate,(Security)}!\\" & _
strComputer & "\root\cimv2")
Set colLogFiles = objWMIService.ExecQuery _
("Select * from Win32_NTEventLogFile " _
& "Where LogFileName='Security'")
For Each objLogFile in colLogFiles
objLogfile.MaxFileSize = (50*1024)
objLogFile.OverwriteOutDated=10
objLogFile.OverwritePolicy=OutDated
objLogFile.Put_(&H20000)
Next
This works for changing the maximum file size, but it does not work for setting the retention cycle.
When I query OverwriteOutDated again after changing it it says ‚0‘ in WMI. When I access it with powershell PS Get-Eventlog -List
It reports
Retain: -1
OverflowAction: DoNotOverwrite
But when I change it via powershell with
Limit-EventLog -LogName Security -RetentionDays 10 -OverflowAction OverwriteOlder
It works
Retain: 10
OverflowAction: OverwriteOlder
There is no error in the WMI call reported. I just seems to mess up the entry. Am I forgetting something when trying to change the retention cycle via WMI?

SendKeys doesn't work from background task

Initial Problem:
I use an external keyboard at the office, so I want the NumLock ON. But when I'm at home I just use the laptop keyboard, so then I get numbers instead of letters and I have to turn NumLock OFF.
Initial Solution:
The below script detects one or two keyboards and turns NumLock ON or OFF as appropriate.
New Problem:
This works perfectly from the command line, but I want it to trigger when I log in and happen automatically. When I run it from Task Scheduler in the background, this line doesn't work:
Shell.SendKeys "{NUMLOCK}"
It fires but doesn't toggle the lock. No errors reported.
UPDATE: If I schedule it to run under my account "only when user is logged on" then it works but shows the cmd window. If I run it under my account or under the SYSTEM account with "whether user is logged in or not" the window goes away nicely but it doesn't work.
Whether from cmd or run as a scheduled task, I get this output when it should toggle the lock:
Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.
Found HID Keyboard Device
Found HID Keyboard Device
numLock is OFF
Toggling Numlock
So the script itself is working correctly.
UPDATE2: Looks like it might have something to do with not having a windows station when running as a background task. Turns out that DetectNumlockConsole.exe isn't working either. That is a simple c# app that returns the results of this line
numLock = Control.IsKeyLocked(Keys.NumLock);
Again, this works when run "only when user is logged on" but not "whether user is logged in or not."
--------- vbs script -----------
set OUT = WScript.StdOut
Set Shell=CreateObject("Wscript.Shell")
Dim KeyCount
KeyCount = 0
Computer = "."
'set NumLock = CheckState
Set WMIService = GetObject("winmgmts:\\" & Computer & "\root\cimv2")
Set Devices = WMIService.ExecQuery ("Select * From Win32_USBControllerDevice")
For Each Device in Devices
DeviceName = Device.Dependent
Quotes = Chr(34)
DeviceName = Replace(DeviceName, Quotes, "")
DeviceNames = Split(DeviceName, "=")
DeviceName = DeviceNames(1)
Set USBDevices = WMIService.ExecQuery ("Select * From Win32_PnPEntity Where DeviceID = '" & DeviceName & "'")
For Each USBDevice in USBDevices
'OUT.WriteLine USBDevice.Description ' Write description to command line to see what to look for
If InStr( LCase( USBDevice.Description ), "keyboard" ) <> 0 Then
KeyCount = KeyCount + 1
OUT.WriteLine "Found " & USBDevice.Description
End If
Next
Next
dim numLock
numLock = Shell.Run("DetectNumlockConsole.exe",0,True)
If (numLock = 0) Then
OUT.WriteLine "numLock is OFF"
Else
OUT.WriteLine "numLock is ON"
End If
' If we have a keyboard, and numlock is OFF
' Or we don't have a keyboard, and numlock is ON
' Then toggle it
If (((KeyCount > 1) AND (numLock = 0)) OR ((KeyCount = 1) AND (numLock = 1))) Then
Shell.SendKeys "{NUMLOCK}" ' *** Problem here, doesn't toggle **
OUT.WriteLine "Toggling Numlock"
End If
That is how windows security works. It is nothing to do with sendkeys per se, but tasks under different security contexts cannot affect other tasks.
As you can see it works when run under the same security context as only run when user logged in does.
It's called process isolation and the principal is that no one can mess with the interactive user for both security and UI principals.

VBS script to scan and install all devices

I'm trying to figure out a way to scan all devices (without drivers installed) and install them one by one automatically.
I've made a simple script that adds/removes a registry value for driver locations, since we have a server with all the current drivers and it's updated frequently, so instead of pointing device manager to that location manually the script does it for me.
Problem is we work in a production environment and we have a lot of different devices to install, and doing it manually takes too long, even with the script i have to click each device and update the driver, the scripts just makes it a little easier by pointing it to the server with the drivers.
So basically i'm try to make the script add the location (this works fine ATM) and them update each device without prompting the user.
Option Explicit
Set ws = WScript.CreateObject("WScript.Shell")
Dim s, ws, rl
rl = "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\"
s = InputBox("Please select what you want to do" & _
vbCrLf & vbTab & "1 - Clear all, set default driver path." & _
vbCrLf & vbTab & "2 - Default path + production drivers" & _
vbCrLf & vbTab & "3 - Default and production path + Skylake drivers")
If s = 1 then
ws.RegWrite rl & "DevicePath", "%SystemRoot%\inf" , "REG_EXPAND_SZ"
ElseIf s = 2 then
ws.RegWrite rl & "DevicePath", "%SystemRoot%\inf; B:\LocalDrivers\; \\ccdsrv01\shares\Resources\Drivers\Client" , "REG_EXPAND_SZ"
ElseIf s = 3 then
ws.RegWrite rl & "DevicePath", "%SystemRoot%\inf; B:\LocalDrivers\; \\ccdsrv01\shares\Resources\Drivers\Client; \\ccdsrv01\shares\Resources\PreProd\SkyBay (Skylake-SunrisePoint)\New" , "REG_EXPAND_SZ"
End If

How to get clientsitename and object status in windows 2000

As we know it's easy to get client site name in windows 2003 via WMI_NTdomain.clientsitename, object status by WMI_NTdomain.status , but that class doesn't exist in Windows 2000. So can you show me how to get those value by script or command line?
My old system is still running well on windows 2000, i don't want to change it at now.
Grab HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Netlogon\Parameters\DynamicSiteName with reg.exe, vbscript, or your favorite scripting/programing language.
Edit:
I admit that I haven't seen W2k for some time now. Does this VB Script output usefull information:
option explicit
dim adSys
Set adSys = CreateObject("ADSystemInfo")
WScript.Echo "SiteName=" & adSys.SiteName
'WScript.Echo "Computername DN=" & adSys.ComputerName
'WScript.Echo "Username DN=" & adSys.UserName
'WScript.Echo "DomainDNSName (Comp)=" & adSys.DomainDNSName
'WScript.Echo "DomainShortName (Comp)=" & adSys.DomainShortName
'WScript.Echo "ForestDNSName (Comp)=" & adSys.ForestDNSName
You could also use the WMI ScriptOMatic to search for the relevent class.

Running a vbs file via a scheduled task on Server 2003

I've been working on modifying an existing vbscript. The wierd part is that when I run the script manually, it works fine. But as soon as I try to run it as a scheduled task, it reports as complete, but doesn't actually do anything. After much troubleshooting, I think I tracked it down to the original CreateObject. Here's the code:
On Error Resume Next
'create an instance of IE
Dim oIE, objFSO, linenum
linenum = 0
Set oIE = CreateObject("InternetExplorer.Application")
'If err.number <> 0 Then linenum = 6
Set objFSO = CreateObject("Scripting.FileSystemObject")
Const ForAppending = 8
Set objTextFile = objFSO.OpenTextFile ("C:\test.txt", ForAppending, True)
'objTextFile.WriteLine(now() & " Internet object created.")
'Execute our URL
'oIE.navigate("<intranet site>")
'objTextFile.WriteLine(now() & " Starting import")
'wait for the window to be closed (exit IE)
'Do Until Err : oIE.visible = True : wsh.sleep 1000 : Loop
'objTextFile.WriteLine(now() & " Import complete.")
if Err.Number <> 0 then
' An exception occurred
objTextFile.WriteLine("Exception:" & vbCrLf & " linenum: " & linenum & vbCrLf & " Error number: " & Err.Number & vbCrLf & " Error source: " & Err.source & vbCrLf & " Error description: " & Err.Description & vbCrLf)
End If
'clean up
'oIE.Quit
'oIE.Visible = False
'Set oIE = Nothing
I've commented most of it out, to narrow it down, and from the logging I added, it spits out the current error:
Exception:
linenum: 0
Error number: -2147467259
Error source:
Error description:
Yes, the source and description lines are blank.
Googling the error doesn't seem to bring up anything useful. So I'm not sure what's going on. Permissions have been checked multiple times, and it's always run as Administrator, the same user as I'm logged in as. The funny part is, this script works fine with Windows 2000. About the only thing I can think of is perhaps the Remote Desktop connection I'm using is somehow interfering with it.
Anyone have any ideas or things I might be able to try to resolve this?
For reference, when you've got problems googling a decimal error number, try converting it to hexadecimal. -2147467259 is the same as 80004005 and if you search for that you'll find that it's quite a common error and usually means that you're denied access to something so even if you're sure that it's not permissions for the things you've checked, it might be worth doing the following checks:
Does the scheduled task run under the same account as you used when you executed the script manually? Otherwise, try doing a RunAs on the script to run as the same user account as the task, if that works, try scheduling the task as your account.
That way you'll know if it's (task vs manual) or if it's (user1 vs user2). Which might make it a little easier to track down the issue.

Resources