JayRHa / EndpointAnalyticsRemediationScripts

MIT License
396 stars 85 forks source link

Error in detect-reboot script #32

Open hotzenwalder opened 1 year ago

hotzenwalder commented 1 year ago

The script used to detect the last time a system was restarted gives an error on my Windows 10 build (19045.2728 Dutch) https://github.com/JayRHa/EndpointAnalyticsRemediationScripts/blob/main/Toast-RebootMessage/detect-reboot.ps1

The error is ` Cannot convert value "1680444208,84456" to type "System.Int32". Error: "De indeling van de invoertekenreeks is onjuist." At line:1 char:1

It's triggered by the command $diff = $now - $poweron, but the problem is probably related to the values of $now and $poweron. The returned values in the original script are

1680444208,84456 for $now and 1680444197,71884 for $differ.

If you replace the , with a . by changing the $now and $differ to these commands, it works.

$now = (Get-Date -UFormat "%s" -Date (Get-Date)) -replace (",",".") $poweron = (Get-Date -UFormat "%s" -Date (Get-Process -Id $pid).StartTime) -replace (",",".")

New values are 1680444208.84456 for $now and 1680444197.71884 for $differ and then the calculations work.

I think it has something to do with the region we run in our enviroment Windows (Dutch), so the characters used for numbering might differ.

johngagefaulkner commented 1 year ago

Considering it's now October 10th, 2023 (more than 6 months since you opened this issue), I'd imagine you've either figured out how to fix the issue or have moved onto something else entirely. Regardless, I just came across this repository a few minutes ago and almost immediately noticed the same issue(s) you're describing.

I rewrote the entire PowerShell script but I'll just share the fix for the specific problem you asked for here:

$ProgressPreference = 'SilentlyContinue'

# Define how often you want your devices to be rebooted
$RebootDeadlineInDays = 7

# Retrieve the Operating System's "Uptime"
$Uptime = Get-ComputerInfo -Property OSUptime | Select-Object OSUptime

if ($Uptime.OSUptime.Days -ge $RebootDeadlineInDays) {
    Write-Host "Operating System has been running for $($Uptime.OSUptime.Days) days! Reboot required."
    Exit 0
} else {
    Write-Host "Operating System was rebooted $($Uptime.OSUptime.Days) days ago! Compliance check: Pass."
    Exit 1
}

Hope that helps! For what it's worth, you can choose to use different measurements of time ("Hours", "Minutes", etc.) by selecting the associated property in the "$Uptime" variable. For example, if you wanted to determine how many hours ago a device rebooted, you could use the following code:

$UptimeInDays = $Uptime.OSUptime.Days
$UptimeInHours = $Uptime.OSUptime.Hours

if ($UptimeInDays -eq 0) {
    Write-Host "Device was rebooted $UptimeInHours hours ago!"
}
hotzenwalder commented 1 year ago

Thanks for the code, but I think this does not take Fast Boot into consideration. With the original script it detects my system was last booted this morning, but when I run your code it tells me my system was last rebooted 12 days ago, so be carefull when you use this code. I use a different code these days, but when I try to paste it here it becomes quite unreadable

johngagefaulkner commented 1 year ago

Thanks for the code, but I think this does not take Fast Boot into consideration. With the original script it detects my system was last booted this morning, but when I run your code it tells me my system was last rebooted 12 days ago, so be carefull when you use this code. I use a different code these days, but when I try to paste it here it becomes quite unreadable

That's fair. I have Fast Startup disabled across all devices in our environment so that's a use-case I never would've come across.

Out of curiosity, what's your result when using the following?

$DeviceLastBootupTime = Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty LastBootupTime
$TimeDifference = (Get-Date) - $DeviceLastBootupTime
Write-Host "Device has been online for $($TimeDifference.Days) days, $($TimeDifference.Hours) hours and $($TimeDifference.Minutes) minutes."

EDIT

*In all fairness*, however, technically your device hasn’t* rebooted in 12 days. With Fast Startup enabled, your device is simply going to sleep and waking up from hibernation.

hotzenwalder commented 1 year ago

The output is 'Device has been online for 13 days, 2 hours and 15 minutes.'. I know it technically has not rebooted since 13 days since it goes into hibernation, that's why we also disable fast boot so updates get installed properly.

Tried pasting my script again, but it won't get any better than this. Hope you can get the output from it you need with and without fast boot enabled

$Last_reboot = Get-ciminstance Win32_OperatingSystem | Select -Exp LastBootUpTime $Check_FastBoot = (Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Power" -ea Silentlycontinue).HiberbootEnabled If(($Check_FastBoot -eq $null) -or ($Check_FastBoot -eq 0)){ $Boot_Event = Get-WinEvent -ProviderName "Microsoft-Windows-Kernel-Boot"| where {$_.ID -eq 27 -and $_.message -like "*0x0*"} If($Boot_Event -ne $null){ $Last_boot = $Boot_Event[0].TimeCreated } } ElseIf($Check_FastBoot -eq 1){ $Boot_Event = Get-WinEvent -ProviderName "Microsoft-Windows-Kernel-Boot"| where {$_.ID -eq 27 -and $_.message -like "*0x1*"} If($Boot_Event -ne $null){ $Last_boot = $Boot_Event[0].TimeCreated } } If($Last_boot -eq $null){ $Uptime = $Last_reboot }Else { If($Last_reboot -ge $Last_boot){ $Uptime = $Last_reboot }Else{ $Uptime = $Last_boot } } $Current_Date = get-date $Diff_boot_time = $Current_Date - $Uptime $Boot_Uptime_Days = $Diff_boot_time.Days $Hour = $Diff_boot_time.Hours $Minutes = $Diff_boot_time.Minutes $Reboot_Time = "$Boot_Uptime_Days day(s)" + ": $Hour hour(s)" + " : $minutes minute(s)" If($Boot_Uptime_Days -ge $Reboot_Delay){ write-host "$Reboot_Time" EXIT 1 }Else { write-output "No Reboot needed" EXIT 0 }

johngagefaulkner commented 1 year ago

I was able to reformat your script to make it readable. The trick to posting any multi-line code is to use three of the backticks before your script and three more after it. You were only using 1 backtick which tells MarkDown that you're wanting to display inline code and not a block of code.

I appreciate you posting your script, though! I hope you don't mind, I've taken it and restructured it to better fit my use-case. I'm posting it here in case you (or anyone else) wants to take a look!

$ProgressPreference = 'SilentlyContinue'
$ErrorActionPreference = 'Stop'
Write-Host "[ Get-DeviceLastBootupTimeWithFastStartup.ps1 ]" -ForegroundColor Green
Write-Host "Determining whether Fast Startup is enabled, please wait... " -NoNewline

# Define Variables
$RebootThresholdInDays = 7
$FastStartupRegistryKeyPath = "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Power"
$IsFastStartupEnabled = (Get-ItemProperty $FastStartupRegistryKeyPath -ErrorAction SilentlyContinue).HiberbootEnabled
Write-Host "Done!" -ForegroundColor Green

# Determine the last bootup time based on Fast Startup setting
$LastOSBootupTime = if ($IsFastStartupEnabled -eq 1) {
    Write-Host "[Fast Startup] Enabled"
    $LatestBootupEvent = Get-WinEvent -ProviderName "Microsoft-Windows-Kernel-Boot" | Where-Object { $_.ID -eq 27 -and $_.Message -like "*0x1*" }
    $LatestBootupEvent[0].TimeCreated
}
elseif (($null -eq $IsFastStartupEnabled) -or ($IsFastStartupEnabled -eq 0)) {
    Write-Host "[Fast Startup] Disabled"
    (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
}
else {
    Write-Host "[WARNING] Unable to determine whether Fast Startup is enabled. Script exiting with exit code 1." -ForegroundColor Yellow
    exit 1
}

# Calculate OS Uptime
if ($null -ne $LastOSBootupTime) {
    Write-Host "[Last OS Bootup Time] $LastOSBootupTime"
    $OsUptime = (Get-Date) - $LastOSBootupTime
    $OsUptimeInDays = $OsUptime.Days
    $OsUptimeInHours = $OsUptime.Hours
    $OsUptimeInMinutes = $OsUptime.Minutes
    Write-Host "[Operating System Uptime] $OsUptimeInDays day(s), $OsUptimeInHours hour(s), $OsUptimeInMinutes minute(s)"

    # Check if reboot is needed
    if ($OsUptimeInDays -ge $RebootThresholdInDays) {
        Write-Host "Uptime threshold ($RebootThresholdInDays days) has been met or exceeded."
        Write-Host "[Result] " -NoNewLine
        Write-Host "Reboot required." -ForegroundColor Yellow
        exit 2
    }
    else {
        Write-Host "Uptime threshold ($RebootThresholdInDays days) has not been met."
        Write-Host "[Result] " -NoNewline
        Write-Host "No reboot required." -ForegroundColor Green
        exit 0
    }
}
else {
    Write-Host "[WARNING] Unable to determine how long the Operating System has been running. Script exiting with exit code 1." -ForegroundColor Yellow
    exit 1
}

Also, here's a screenshot of the output from the script above: image