|
Server : Apache/2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.2.12 System : Windows NT SERVER-PC 10.0 build 26200 (Windows 11) AMD64 User : ServerPC ( 0) PHP Version : 8.2.12 Disable Function : NONE Directory : C:/Windows/diagnostics/system/Apps/ |
Upload File : |
# Copyright © 2016, Microsoft Corporation. All rights reserved.
# :: ======================================================= ::
<#
DESCRIPTION:
Utils_Apps.ps1 is used as common scripts by Apps Troubleshooter
FUNCTIONS:
Get-CurrentUser
Get-PendingReboot
#>
#====================================================================================
# Functions
#====================================================================================
Function Write-ExceptionTelemetry($FunctionName, [System.Management.Automation.ErrorRecord] $ex)
{
<#
DESCRIPTION:
Writes script error information into telemetry stream
EXAMPLE:
try
{
0 / 0
}
catch [System.Exception]
{
Write-ExceptionTelemetry "DivideByZeroTest" $_
}
#>
$ExceptionMessage = $ex.Exception.Message
$ScriptFullPath = $ex.InvocationInfo.ScriptName
$ExceptionScript = [System.IO.Path]::GetFileName($ScriptFullPath)
$ExceptionScriptLine = $ex.InvocationInfo.ScriptLineNumber
$ExceptionScriptColumn = $ex.InvocationInfo.OffsetInLine
Write-DiagTelemetry "ScriptError" "$ExceptionScript\$FunctionName\$ExceptionScriptLine\$ExceptionScriptColumn\$ExceptionMessage"
}
function Get-CurrentUser
{
<#
DESCRIPTION:
This function will list the information about currently logged in user. It will detect currently logged in user
via getting the owner of msdt.exe process.
EXAMPLE:
PS C:\> Get-CurrentUser
Domain : DESKTOP-URI2BR4
User : Administrator
SID : S-1-5-21-2146773085-903363285-719344707-1888833
FullName : DESKTOP-URI2BR4\Administrator
LocalProfilePath : C:\Users\Administrator
LastUseTime : 3/5/2016 5:12:02 AM
IsCurrentlyLoggedOn : True
IsTemporaryProfile : False
This example will return an object which contains above properties respective to currently logged in or impersonated user.
#>
# Getting parent msdt.exe processes
$msdtProcess = Get-WmiObject -Class Win32_Process -Filter "Name = 'msdt.exe'" |
Sort-Object -Property CreationDate -Descending | Select-Object -Last 1
if($msdtProcess)
{
# Retrieving user information from msdt.exe processes
$userDomain = ($msdtProcess.GetOwner()).Domain
$userName = ($msdtProcess.GetOwner()).User
$ntAccount = New-Object System.Security.Principal.NTAccount("$userDomain\$userName")
$sid = $ntAccount.Translate([System.Security.Principal.SecurityIdentifier]).Value
$win32UserProfiles = Get-WmiObject -Class Win32_UserProfile -Filter "SID = '$sid'"
$currentUser = "" | Select Domain, User, SID, FullName, LocalProfilePath, LastUseTime, IsCurrentlyLoggedOn, IsTemporaryProfile
foreach($win32UserProfile in $win32UserProfiles)
{
if($win32UserProfile.Loaded)
{
# Populating user profile
$currentUser.Domain = $userDomain
$currentUser.User = $userName
$currentUser.SID = $sid
$currentUser.FullName = ("$userDomain\$userName")
$currentUser.LocalProfilePath = $win32UserProfile.LocalPath
$currentUser.LastUseTime = ([WMI]'').ConvertToDateTime(($win32UserProfile.LastUseTime | Where {$_ -ne $null}))
$currentUser.IsCurrentlyLoggedOn = $win32UserProfile.Loaded
$currentUser.IsTemporaryProfile = ($win32UserProfile.Status -eq 1) # (0 = Default/Unset, 1 = Temporary, 2 = Roaming, 4 = Mandatory, 8 = Corrupted)
break
}
}
$currentUser
}
}
function Get-PendingReboot
{
<#
SYNOPSIS:
Gets the pending reboot status on a local computer.
DESCRIPTION:
This function will query the registry on a local or remote computer and determine if the
system is pending a reboot, from Microsoft updates, Configuration Manager Client SDK, Pending Computer
Rename, Domain Join or Pending File Rename Operations. For Windows 2008+ the function will query the
CBS registry key as another factor in determining pending reboot state. "PendingFileRenameOperations"
and "Auto Update\RebootRequired" are observed as being consistent across Windows Server 2003 & 2008.
CBServicing : Component Based Servicing (Windows 2008+)
WindowsUpdate : Windows Update / Auto Update (Windows 2003+)
CCMClientSDK : SCCM 2012 Clients only (DetermineIfRebootPending method) otherwise $null value
PendingComputerRename : Detects either a computer rename or domain join operation (Windows 2003+)
PendingFileRename : PendingFileRenameOperations (Windows 2003+)
PendingFileRenameValue : PendingFileRenameOperations registry value; used to filter if needed, some Anti-Virus
leverage this key for def/dat removal, giving a false positive PendingReboot
EXAMPLE:
PS C:\> Get-PendingReboot
CBServicing : False
WindowsUpdate : True
CCMClient : False
PendingComputerRename : False
PendingFileRename : False
PendingFileRenameValue : {\??\C:\Users\Administrator\AppData\Local\Temp\nsz994B.tmp\p\syschk.dll, , \??\C:\Users\Administrator\AppData\Local\Temp\nsz994B.tmp\p\, ...}
RebootPending : True
This example will query the local machine for pending reboot information.
LINK:
Component-Based Servicing:
http://technet.microsoft.com/en-us/library/cc756291(v=WS.10).aspx
PendingFileRename/Auto Update:
http://support.microsoft.com/kb/2723674
http://technet.microsoft.com/en-us/library/cc960241.aspx
http://blogs.msdn.com/b/hansr/archive/2006/02/17/patchreboot.aspx
SCCM 2012/CCM_ClientSDK:
http://msdn.microsoft.com/en-us/library/jj902723.aspx
#>
try
{
$Computer = $env:COMPUTERNAME
# Setting pending values to false
$CBSRebootPending = $PendingComputerRename = $PendingFileRename = $SCCM = $Pending = $false
# Making registry connection to the computer
$HKLM = [UInt32] '0x80000002'
$WmiRegistryConnection = [WMIClass] "\\$Computer\root\default:StdRegProv"
# Querying the CBS Registry Key
$RegSubKeysCBS = $WmiRegistryConnection.EnumKey($HKLM,'SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\')
$CBSRebootPending = $RegSubKeysCBS.sNames -Contains 'RebootPending'
# Query WUAU from the registry
$RegWUAURebootRequired = $WmiRegistryConnection.EnumKey($HKLM,'SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\')
$WUAURebootRequired = $RegWUAURebootRequired.sNames -contains 'RebootRequired'
# Query PendingFileRenameOperations from the registry
$RegSubKeySM = $WmiRegistryConnection.GetMultiStringValue($HKLM,'SYSTEM\CurrentControlSet\Control\Session Manager\","PendingFileRenameOperations')
$RegValuePFRO = $RegSubKeySM.sValue
# Query JoinDomain key from the registry - These keys are present if pending a reboot from a domain join operation
$Netlogon = $WmiRegistryConnection.EnumKey($HKLM,'SYSTEM\CurrentControlSet\Services\Netlogon').sNames
$PendingDomainJoin = ($Netlogon -contains 'JoinDomain') -or ($Netlogon -contains 'AvoidSpnSet')
# Query ComputerName and ActiveComputerName from the registry
$ActiveComputerName = $WmiRegistryConnection.GetStringValue($HKLM,'SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName\','ComputerName')
$ComputerName = $WmiRegistryConnection.GetStringValue($HKLM,'SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName\','ComputerName')
if (($ActiveComputerName -ne $ComputerName) -or $PendingDomainJoin)
{
$PendingComputerRename = $true
}
# If PendingFileRenameOperations has a value set $RegValuePFRO variable to $true
if ($RegValuePFRO)
{
$PendingFileRename = $true
}
# Determine SCCM 2012 Client Reboot Pending Status
# To avoid nested 'if' statements and unneeded WMI calls to determine if the CCM_ClientUtilities class exist, setting EA = 0
$CCMClientSDK = $null
$CCMSplat = @{
NameSpace = 'ROOT\ccm\ClientSDK'
Class = 'CCM_ClientUtilities'
Name = 'DetermineIfRebootPending'
ComputerName = $Computer
ErrorAction = 'Stop'
}
try
{
$CCMClientSDK = Invoke-WmiMethod @CCMSplat
}
catch [System.UnauthorizedAccessException]
{
$CcmStatus = Get-Service -Name CcmExec -ComputerName $Computer -ErrorAction SilentlyContinue
if ($CcmStatus.Status -ne 'Running')
{
Write-Warning "$Computer`: Error - CcmExec service is not running."
$CCMClientSDK = $null
}
Write-ExceptionTelemetry "Get-PendingReboot" $_
}
catch
{
$CCMClientSDK = $null
Write-ExceptionTelemetry "Get-PendingReboot" $_
}
if ($CCMClientSDK)
{
if ($CCMClientSDK.ReturnValue -ne 0)
{
Write-Warning "Error: DetermineIfRebootPending returned error code $($CCMClientSDK.ReturnValue)"
}
if ($CCMClientSDK.IsHardRebootPending -or $CCMClientSDK.RebootPending)
{
$SCCM = $true
}
}
else
{
$SCCM = $null
}
# Creating Custom PSObject and Select-Object Splat
$SelectSplat = @{
Property = (
'CBServicing',
'WindowsUpdate',
'CCMClientSDK',
'PendingComputerRename',
'PendingFileRename',
'PendingFileRenameValue',
'RebootPending'
)}
New-Object -TypeName PSObject -Property @{
CBServicing = $CBSRebootPending
WindowsUpdate = $WUAURebootRequired
CCMClientSDK = $SCCM
PendingComputerRename = $PendingComputerRename
PendingFileRename = $PendingFileRename
PendingFileRenameValue = $RegValuePFRO
RebootPending = ($PendingComputerRename -or $CBSRebootPending -or $WUAURebootRequired -or $SCCM -or $PendingFileRename)
} | Select-Object @SelectSplat
}
catch
{
Write-Warning "$Computer`: $_"
# Updating diagnostics report
if ($ErrorLog) {
Out-File -InputObject "$Computer`,$_" -FilePath $ErrorLog -Append
}
Write-ExceptionTelemetry "Get-PendingReboot" $_
}
}