<# This script interactively runs a remote GPResult, letting admin select user then collects the results Alan Kaplan www.akaplan.com 7/22/20 #> param ( [Parameter(Mandatory = $True)] [string]$Computer ) Add-Type -assemblyname Microsoft.visualBasic Add-Type -AssemblyName System.Windows.Forms Function Select-FolderDialog { Param ( # [Parameter(Mandatory = $False)] $RootFolder = 'MyComputer', [Parameter(Mandatory = $false)] [bool]$NewFolderBtn = $true, [Parameter(Mandatory = $false)] [string]$Title = "" ) $FolderBrowser = New-Object System.Windows.Forms.FolderBrowserDialog -Property @{ RootFolder = $RootFolder ShowNewFolderButton = $NewFolderBtn Description = $Title } $Show = $FolderBrowser.ShowDialog() If ($Show -eq "OK") { Return $FolderBrowser.SelectedPath } Else { Write-warning "Operation cancelled by user." Pause Exit } } Function Get-ComputerFQDN { $owmi = get-wmiobject -class Win32_computerSystem [string]"$($owmi.name).$($owmi.domain)" } Function Convert-DNtoNTName ($strDN) { $NameTranslate = New-Object -ComObject "NameTranslate" Invoke-Method $NameTranslate "Init" (3, "") Invoke-Method $NameTranslate "Set" (1, $strDN) Invoke-Method $NameTranslate "Get" (3) [void][System.Runtime.Interopservices.Marshal]::ReleaseComObject($NameTranslate) } #Bill Stewart function Invoke-Method([__ComObject] $object, [String] $method, $parameters) { $object.GetType().InvokeMember($method, "InvokeMethod", $NULL, $object, $parameters) } Function Format-String ([System.String]$String) { #https://lazywinadmin.com/2015/05/powershell-remove-diacritics-accents.html [System.Text.NormalizationForm]$NormalizationForm = "FormD" $Normalized = $String.Normalize($NormalizationForm) $NewString = New-Object -TypeName System.Text.StringBuilder $normalized.ToCharArray() | ForEach-Object -Process { if ([Globalization.CharUnicodeInfo]::GetUnicodeCategory($_) -ne [Globalization.UnicodeCategory]::NonSpacingMark) { [void]$NewString.Append($_) } } $($NewString -as [string]).trim() } $MyPC = Get-ComputerFQDN $logfolder = Select-FolderDialog -RootFolder Desktop -title "Select location for the GPResult file" $params = @{ Namespace = 'root\rsop\user' Class = '__NAMESPACE' ErrorAction = 'Stop' } if ($Computer -ne $MyPC) { if ((Test-Connection $Computer -Quiet -count 2) -eq $false) { Write-Warning "Unable to ping $Computer" Exit } $params.Add('ComputerName', $Computer) } #Get list of domain network user with RSOP Data on system Write-Progress "Getting list of users on $computer available for GPResult" Try { $RSOP = Get-WmiObject @Params $RSOPSids = ($RSOP.name).replace('_', '-') | Where-Object { $_.tostring().startsWith('S-1') } } Catch { write-warning $error[0].Exception.Message Exit } #Get User Info for each SID $user = $RSOPSids | ForEach-Object { $SID = $_ $IDRef = ([adsi]"LDAP://") $strDN = $IDRef.Distinguishedname.Value $NTName = Format-String(Convert-DNtoNTName $strDN) [PSCustomObject]@{ Name = $IDRef.name.Value SamAccountName = $IDRef.SamAccountname.Value NTName = $NTName Description = $IDRef.Description.Value DistinguishedName = $strDN } } | Sort-Object Name | Out-GridView -PassThru -Title "Select a user for GPResult on $computer" if ($user) { $NTName = $user.NTName $uname = $User.SamAccountName } Else { Exit } Write-Progress -Completed " " #menu $msg = @" Running GPResult on $computer for $uname. Do you want to: 1) Get a standard html report 2) Get a verbose text report 0) Quit "@ [int]$retVal = [Microsoft.VisualBasic.Interaction]::InputBox($msg, "GPResult Report Type", 1) switch ($retVal) { 1 { $bVerbose = $false ; break } 2 { $bVerbose = $true ; break } Default { Exit } } $logfile = "$logfolder\$uname on $Computer GPResult" Write-Progress "Getting GPOs applied for $uname on $computer" Try { $s = New-PSSession -ComputerName $computer -ErrorAction Stop } Catch { Write-Warning $_ Pause Exit } if ($bVerbose) { $logfile = "$logfile`.txt" invoke-command -ScriptBlock { & cmd /c "C:\windows\system32\gpresult.exe" /user $Using:NTName /v } -Session $s | Tee-Object -FilePath $logfile } Else { $logfile = "$logfile`.htm" $TempRemoteFileUNC = "\\$computer\c$\Gpresult.htm" invoke-command -ScriptBlock { & cmd /c "C:\windows\system32\gpresult.exe" /user $using:NTName /h c:\gpresult.htm /f } -Session $s #Pausing for file to complete writing Start-Sleep -Seconds 3 if (Test-Path $TempRemoteFileUNC) { Copy-Item $TempRemoteFileUNC $logfile -Force Remove-Item $TempRemoteFileUNC -Force } } Write-Progress "Done" if (test-path -Path $logfile) { Start-Process $logfile -Wait } Else { Write-Warning "Failed to collect requested data" Pause } #Cleanup Session Get-PSSession | Remove-PSSession