<# Alan Kaplan www.akaplan.com GUI to Logoff/Shutdown remote computer using WMI 8/7/2017,9/26/19 #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string] $Computer ) Add-Type -assemblyname Microsoft.visualBasic Function Get-ShutdownType() { #build menu $msg = @" = $Computer = 1 - Logoff 2 - Force Logoff (NO SAVE) 3 - Powerdown 4 - Force Powerdown (NO SAVE) 5 - Reboot 6 - Force Reboot (NO SAVE) ===================== 7 - Ping test 8 - Check for logged on user(s) 9 - Send User(s) Message 0 - Quit NOTE: Using force will close programs without saving changes! "@ $iAction = [Microsoft.VisualBasic.Interaction]::InputBox($msg, "Choose Action:", "0") switch ($iAction) { 1 { #Logoff $Script:WMIArg = 0 $script:msg = "Logoff for all users sent to $Computer" Break } 2 { #Force Logoff $Script:WMIArg = 4 $script:msg = "Force logoff for all users sent to $Computer" Break } 3 { #Powerdown $Script:WMIArg = 8 $script:msg = "Powerdown sent to $Computer" Break } 4 { #Force Powerdown $Script:WMIArg = 12 $script:msg = "Force Powerdown sent to $Computer" Break } 5 { #Reboot $Script:WMIArg = 2 $script:msg = "Reboot sent to $Computer" Break } 6 { #Force Reboot $Script:WMIArg = 6 $script:msg = "Force Reboot sent to $Computer" Break } 7 { #Ping if (Test-Connection $Computer -Count 2 -Quiet) { [Microsoft.VisualBasic.Interaction]::MsgBox("$Computer is online", [Microsoft.VisualBasic.MsgBoxStyle]::OkOnly, "Ping Test") | Out-Null } ELSE { [Microsoft.VisualBasic.Interaction]::MsgBox("$Computer failed to reply to ping", [Microsoft.VisualBasic.MsgBoxStyle]::Critical, "Ping Test") | Out-Null } Get-ShutdownType } 8 { #Check for logged on users Get-LoggedOnUsers Break } 9 { #Send logged on users a message Send-Message Break } Default { Exit} } } Function Invoke-WMIAction () { Try { $retval = Invoke-WmiMethod -computername $Computer -Path "root\cimv2:Win32_OperatingSystem=@" -Name Win32Shutdown -ArgumentList $Script:WMIArg -ErrorAction stop if ($retval.ReturnValue -eq 0) { Write-host $script:msg } ELSE { $errmsg = "$script:msg, but failed with error: " + [ComponentModel.Win32Exception]$retval.ReturnValue Write-warning $errmsg } } Catch { #This may never be reached $errmsg = "$msg, but failed with error: " + $error[0].Exception.Message Write-warning $errmsg } Pause } Function Get-LoggedOnUserDetails() { Write-progress "Getting Logged On Users" $wQL = "Select * from Win32_LogonSession Where LogonType = 2 OR LogonType = 10" $colSessions = get-wmiobject -query $wql -computername $computer if ($colSessions.Count -eq 0) { Write-warning "No interactive users found on $computer" pause } ELSE { Write-Progress "Getting sessions on $computer" $QUserTxt = query User /server:$computer #loosely based on Get-ComputerUser by Boe Prox 01 Nov 2010 $UserInfo = 1..($QUserTxt.count - 1) | ForEach-Object { [PSCustomObject] @{ UserName = $QUserTxt[$_].Substring(1, 20).Trim() SessionName = $QUserTxt[$_].Substring(22, 20).Trim() ID = $QUserTxt[$_].Substring(42, 3).Trim() State = $QUserTxt[$_].Substring(45, 8).Trim() IdleTime = $QUserTxt[$_].Substring(53, 12).Trim() LogonTime = $QUserTxt[$_].Substring(64).Trim() } } $UserInfo | Out-GridView -Title "Users on $computer" -Wait } } Function Get-LoggedOnUsers() { $UserCount = (quser /server:$computer).count - 1 if ($UserCount -gt 0) { $msg = "$usercount sessions found. Do you want to see logged on user details? (This can take a while)" $btn = [Microsoft.VisualBasic.MsgBoxStyle]::Question + [Microsoft.VisualBasic.MsgBoxStyle]::YesNo $retval = [Microsoft.VisualBasic.Interaction]::MsgBox($msg, $btn, "Sessions") if ($Retval -eq "Yes") { Get-LoggedOnUserDetails } } ELSE { $btn = [Microsoft.VisualBasic.MsgBoxStyle]::Question + [Microsoft.VisualBasic.MsgBoxStyle]::Information $retval = [Microsoft.VisualBasic.Interaction]::MsgBox("No users are logged onto $Computer", $btn , "No Sessions") } Get-ShutdownType } Function Send-Message() { $msg = "Send what message to logged on users of $computer`?" $msg = [Microsoft.VisualBasic.Interaction]::InputBox($msg, "Message", "Please save your work. Logoff in 1 minute!") $cmd = "msg * /Server:$computer /Time:30 `"$msg`"" Invoke-Expression $cmd Get-ShutdownType } #Script Begins. Ensure admin rights If (!([bool](([System.Security.Principal.WindowsIdentity]::GetCurrent()).groups -match "S-1-5-32-544"))) { $title = "Permissions Issue" $msg = "You are not an administrator on this computer. Does $env:Username have admin rights on the remote computer?" $retval = [Microsoft.VisualBasic.Interaction]::MsgBox($msg, 'YesNoCancel,defaultbutton2,Question', $title) if ($retval -ne 'Yes') { Exit} } if ($null -eq $computer){ $msg = "Enter the FQDN of the computer you wish to Shutdown / Reboot / Logoff" $title = "Remote Shutdown / Reboot / Logoff" $Computer = [Microsoft.VisualBasic.Interaction]::InputBox($msg, $title, [system.net.dns]::GetHostEntry('localhost').hostname) } if ($Computer -eq '' ) { Exit} Else { $Computer = $Computer.ToUpper() } Get-ShutdownType Invoke-WMIAction