????
Current Path : C:/Windows/diagnostics/system/Apps/ |
Current File : C:/Windows/diagnostics/system/Apps/Utils_Apps.ps1 |
# 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" $_ } }