Need help with Powershell Code.

Ray C 20 Reputation points
2023-06-01T16:40:47.5866667+00:00

Hello. I am trying to create a PowerShell script to do a few things. I will use a scheduled task to run the script. I want to have a bunch of workstations reboot every Sunday morning with a 4 hour count down timer. Ideally the timer would be a simple pop up box that just counts down 4 hours and can not be closed by the user.

Being that I am vaguely familiar with PS, I am stuck on some of my code and need to figure out the rest which I am struggling with that as well.

Here is what I have so far. Any help / direction would be greatly appreciated. Thank you!

# Set the minimum number of days of uptime to issue the warning.
WarnAfterDays = 1

# Set the initial restart countdown hours.
RestartCountdownHours = 4

Set objShell = WScript.CreateObject("WScript.Shell")
Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate,(Shutdown)}!\\.\root\cimv2")
Set colComp = objWMI.ExecQuery("SELECT LastBootUpTime FROM Win32_OperatingSystem")

For (( Each item In colComp )
    dlastReboot = WMIDateStringToDate(item.LastBootUpTime)
    dDateTime = Now()
    dDiff = DateDiff("d", dlastbootuptime, dDateTime)
    
    If (dDiff >= WarnAfterDays Then)
        If (RestartCountdownHours > 0 Then
            MsgBox "Restart in " '&' RestartCountdownHours '&' " hours", vbInformation + vbOKOnly, "Restart Reminder"
        Else
            MsgBox "Restarting in 5 minutes", vbInformation + vbOKOnly, "Restart Reminder"
            # Set the restart command here (e.g., objShell.Run "shutdown /r /t 300")
        End If
    Else
        MsgBox "Restart Now", vbInformation + vbOKOnly, "Restart Reminder"
        # Set the restart command here (e.g., objShell.Run "shutdown /r /t 0")
    End If
Next

Function WMIDateStringToDate(dtmInstallDate)
    WMIDateStringToDate = CDate(Mid(dtmInstallDate, 5, 2) '&' "/" '&' _)
                               Mid(dtmInstallDate, 7, 2) '&' "/" '&' Left(dtmInstallDate, 4) _
                               & " " '&' Mid(dtmInstallDate, 9, 2) '&' ":" '&' _
                               Mid(dtmInstallDate, 11, 2) '&' ":" '&' Mid(dtmInstallDate, _
                               13, 2)

also added are the errors being generated.

At line:13 char:21
+     dDateTime = Now()
+                     ~
An expression was expected after '('.
At line:13 char:22
+     dDateTime = Now()
+                      ~
Missing closing ')' after expression in 'for' statement.
At line:14 char:26
+     dDiff = DateDiff("d", dlastbootuptime, dDateTime)
+                          ~
Missing expression after ','.
At line:14 char:27
+     dDiff = DateDiff("d", dlastbootuptime, dDateTime)
+                           ~~~~~~~~~~~~~~~
Unexpected token 'dlastbootuptime' in expression or statement.
At line:14 char:26
+     dDiff = DateDiff("d", dlastbootuptime, dDateTime)
+                          ~
Missing closing ')' in expression.
At line:14 char:53
+     dDiff = DateDiff("d", dlastbootuptime, dDateTime)
+                                                     ~
Unexpected token ')' in expression or statement.
At line:16 char:36
+     If (dDiff >= WarnAfterDays Then)
+                                    ~
Missing statement block after If ( condition ).
At line:18 char:13
+             MsgBox "Restart in " '&' RestartCountdownHours '&' " hour ...
+             ~~~~~~
Missing closing ')' after expression in 'If' statement.
At line:29 char:30
+ Function WMIDateStringToDate(dtmInstallDate)
+                              ~
Missing ')' in function parameter list.
At line:29 char:44
+ Function WMIDateStringToDate(dtmInstallDate)
+                                            ~
Unexpected token ')' in expression or statement.
Not all parse errors were reported.  Correct the reported errors and try again.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : ExpectedExpression
PowerShell
PowerShell
A family of Microsoft task automation and configuration management frameworks consisting of a command-line shell and associated scripting language.
2,315 questions
0 comments No comments
{count} votes

Accepted answer
  1. Rich Matheisen 45,831 Reputation points
    2023-06-01T22:44:19.2733333+00:00

    Here's your script, rewritten in PowerShell (change the "$true" to "$false" in the Restart-Computer cmdlet if you want the restart to do anything):

    Add-Type -AssemblyName PresentationCore,PresentationFramework
    # Set the minimum number of days of uptime to issue the warning.
    $WarnAfterDays = 1
    
    # Set the initial restart countdown hours.
    $RestartCountdownHours = 4
    
    # The CIM object has a DateTime type for LastBootupTime. No conversion necessary
    (Get-CimInstance Win32_OperatingSystem).LastBootupTime |
        ForEach-Object{
            $dlastReboot = $_
            $dDiff = (Get-Date) - $dlastReboot
            If ($dDiff.TotalDays -ge $WarnAfterDays){   # TotalDays takes into account fractional days E.G., 1 Day and Twelve Hours = 1.5 instead of 
                                                        # the "Days" property that would have returned a value of 1 and forced a reboot
                If ($RestartCountdownHours -gt 0){
                    [System.Windows.MessageBox]::Show(("Restart in {0} hours" -f $RestartCountdownHours),"Restart Reminder",'OK','Information')
                    Start-Sleep -Seconds ($RestartCountdownHours * 60 * 60)
                    Restart-Computer -Force -WhatIf:$true
                }
                Else{
                    [System.Windows.MessageBox]::Show("Restarting in 5 minutes", "Restart Reminder", 'OK', 'Information')
                    Start-Sleep -Seconds (5 * 60)
                    Restart-Computer -Force -WhatIf:$true
                }
            }
            Else{
                [System.Windows.MessageBox]::Show("Restarting now", "Restart Reminder", 'OK', 'Information')
                Restart-Computer -Force -WhatIf:$true
            }
        }
    

    As @MotoX80 pointed out, you need a desktop to display the message box and scheduled tasks don't have one (at least in the Scheduled Task GUI), so it's unlikely this will work the way you expect it to.

    1 person found this answer helpful.

2 additional answers

Sort by: Most helpful
  1. MotoX80 32,836 Reputation points
    2023-06-01T17:41:08.9666667+00:00

    Well the main problem is that what you posted is not Powershell code. It's VB script. That won't work. Download and review this pdf. It will walk you though the basics of Powershell.

    https://www.sapien.com/books_training/Windows-PowerShell-4

    Windows comes with Powershell_ISE that you can use for development. Microsoft isn't enhancing it anymore, but for some basic stuff it works just fine. And typically it's already installed.

    There are ISE videos here that should get you going. By using the ISE it will help you with syntax errors.

    https://www.sportskeeda.com/gaming-tech/how-use-windows-powershell-ise

    The problem you are going to have using a scheduled task is that the task must run as the desktop user account in order for it's window to be visible.

    Your best bet is to use code that other users have developed as a starting point. That way the basic code is already written. You can then try to customize it for your needs.

    https://www.bing.com/search?q=powershell+sample+to+patch+workstations

    1 person found this answer helpful.
    0 comments No comments

  2. MotoX80 32,836 Reputation points
    2023-06-02T01:46:29.6733333+00:00

    Here's something that I came up with a few years ago that might be of value. You have one script that interacts with the desktop user and one that runs as the system account to do things like install patches, reboot the pc, etc.

    See my scripts.

    https://learn.microsoft.com/en-us/answers/questions/246173/scheduled-task-to-launch-powershell-script-in-syst?sort=oldest&orderBy=Helpful

    You define a scheduled task that runs as the system account and executes server.ps1. That script does the meat of the work. It defines and starts a second task that runs in the context of the desktop user and communicates back to server.ps1 via a temporary file.

    The user can kill client.ps1 but he can't kill the server.ps1 task.

    1 person found this answer helpful.