#region .NET
############ Add a .NET Framework type: namespace Resoultion class Displays
$pinvokeCode = @"
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
namespace Resolution
{
[StructLayout(LayoutKind.Sequential)]
public struct DEVMODE1
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string dmDeviceName;
public short dmSpecVersion;
public short dmDriverVersion;
public short dmSize;
public short dmDriverExtra;
public int dmFields;
public short dmOrientation;
public short dmPaperSize;
public short dmPaperLength;
public short dmPaperWidth;
public short dmScale;
public short dmCopies;
public short dmDefaultSource;
public short dmPrintQuality;
public short dmColor;
public short dmDuplex;
public short dmYResolution;
public short dmTTOption;
public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string dmFormName;
public short dmLogPixels;
public short dmBitsPerPel;
public int dmPelsWidth;
public int dmPelsHeight;
public int dmDisplayFlags;
public int dmDisplayFrequency;
public int dmICMMethod;
public int dmICMIntent;
public int dmMediaType;
public int dmDitherType;
public int dmReserved1;
public int dmReserved2;
public int dmPanningWidth;
public int dmPanningHeight;
};
[Flags()]
public enum DisplayDeviceStateFlags : int
{
/// The device is part of the desktop.
AttachedToDesktop = 0x1,
MultiDriver = 0x2,
/// The device is part of the desktop.
PrimaryDevice = 0x4,
/// Represents a pseudo device used to mirror application drawing for remoting or other purposes.
MirroringDriver = 0x8,
/// The device is VGA compatible.
VGACompatible = 0x10,
/// The device is removable; it cannot be the primary display.
Removable = 0x20,
/// The device has more display modes than its output devices support.
ModesPruned = 0x8000000,
Remote = 0x4000000,
Disconnect = 0x2000000
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct DISPLAY_DEVICE
{
[MarshalAs(UnmanagedType.U4)]
public int cb;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=32)]
public string DeviceName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
public string DeviceString;
[MarshalAs(UnmanagedType.U4)]
public DisplayDeviceStateFlags StateFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
public string DeviceID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
public string DeviceKey;
}
class User_32
{
[DllImport("user32.dll")]
public static extern int EnumDisplaySettings(string deviceName, int modeNum, ref DEVMODE1 devMode);
[DllImport("user32.dll")]
public static extern int ChangeDisplaySettings(ref DEVMODE1 devMode, int flags);
[DllImport("user32.dll")]
public static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, uint dwFlags);
public const int ENUM_CURRENT_SETTINGS = -1;
public const int CDS_UPDATEREGISTRY = 0x01;
public const int CDS_TEST = 0x02;
public const int DISP_CHANGE_SUCCESSFUL = 0;
public const int DISP_CHANGE_RESTART = 1;
public const int DISP_CHANGE_FAILED = -1;
}
public class Displays
{
public static IList GetDisplayNames()
{
var returnVals = new List();
for(var x=0U; x<1024; ++x)
{
DISPLAY_DEVICE outVar = new DISPLAY_DEVICE();
outVar.cb = (short)Marshal.SizeOf(outVar);
if(User_32.EnumDisplayDevices(null, x, ref outVar, 1U))
{
returnVals.Add(outVar.DeviceName);
}
}
return returnVals;
}
public static string GetCurrentResolution(string deviceName)
{
string returnValue = null;
DEVMODE1 dm = GetDevMode1();
if (0 != User_32.EnumDisplaySettings(deviceName, User_32.ENUM_CURRENT_SETTINGS, ref dm))
{
returnValue = dm.dmPelsWidth + "," + dm.dmPelsHeight;
}
return returnValue;
}
public static IList GetResolutions()
{
var displays = GetDisplayNames();
var returnValue = new List();
foreach(var display in displays)
{
returnValue.Add(GetCurrentResolution(display));
}
return returnValue;
}
private static DEVMODE1 GetDevMode1()
{
DEVMODE1 dm = new DEVMODE1();
dm.dmDeviceName = new String(new char[32]);
dm.dmFormName = new String(new char[32]);
dm.dmSize = (short)Marshal.SizeOf(dm);
return dm;
}
}
}
"@
Add-Type $pinvokeCode
#endregion .NET
#region Functions
Function GetDisplayMonitorResolutions {
$res = [Resolution.Displays]::GetResolutions()
$res_str = @()
$res_str += $res | ForEach-Object {if ($_) {([string]$_).Replace(",","x")}}
$res_str
}
Function GetDisplayMonitors{
$strReturn = @()
try {
$MonsObj = Get-WmiObject WmiMonitorID -Namespace root\wmi -ErrorAction Stop |
ForEach-Object {
[PSCustomObject]@{
Manufacturer = [System.Text.Encoding]::ASCII.GetString($_.ManufacturerName).Trim(0x00)
Name = [System.Text.Encoding]::ASCII.GetString($_.UserFriendlyName).Trim(0x00)
Serial = [System.Text.Encoding]::ASCII.GetString($_.SerialNumberID).Trim(0x00)
}
}
$strReturn += $MonsObj | ForEach-Object {"$($_.Name) [Serial $($_.Serial)]"}
}
Catch {
$strReturn += "[Monitor model detection requires run as admin]"
}
$strReturn
}
Function GetDisplayControllers {
$controllers = @()
$controllers += Get-WmiObject win32_videocontroller | Select-Object -ExpandProperty caption
$controllers
}
Function IsAdmin()
{
<#
.SYNOPSIS
Checks if the running process has elevated priviledges.
.DESCRIPTION
To get elevation with powershell, right-click the .ps1 and run as administrator - or run the ISE as administrator.
.EXAMPLE
if (-not(IsAdmin))
{
write-host "No admin privs here, run this elevated"
return
}
#>
$wid=[System.Security.Principal.WindowsIdentity]::GetCurrent()
$prp=new-object System.Security.Principal.WindowsPrincipal($wid)
$adm=[System.Security.Principal.WindowsBuiltInRole]::Administrator
$IsAdmin=$prp.IsInRole($adm)
$IsAdmin
}
Function IsLocalAdmin
{ ## if the user is in the local admins group
$null -ne (whoami /groups /fo csv |
ConvertFrom-Csv |
Where-Object { $_.SID -eq "S-1-5-32-544" })
}
Function LocalAdmins
{
## Show Local admins
$administratorsAccount = Get-WmiObject Win32_Group -filter "LocalAccount=True AND SID='S-1-5-32-544'"
$administratorQuery = "GroupComponent = `"Win32_Group.Domain='" + $administratorsAccount.Domain + "',NAME='" + $administratorsAccount.Name + "'`""
$locadmins_wmi = Get-WmiObject Win32_GroupUser -filter $administratorQuery | Select-Object PartComponent
$locadmins = @()
$azadmins = @()
$count = 0
$account_warnings = 0
$msg_accounts =""
foreach ($locadmin_wmi in $locadmins_wmi)
{
$user1 = $locadmin_wmi.PartComponent.Split(".")[1]
$user1 = $user1.Replace('"',"")
$user1 = $user1.Replace('Domain=',"")
$user1 = $user1.Replace(',Name=',"\")
$Status = ""
$domainname = $user1.Split("\")[0]
$accountname = $user1.Split("\")[1]
$locadmin_info = Get-LocalUser $accountname -ErrorAction SilentlyContinue
if ($locadmin_info)
{
if (-not ($locadmin_info.Enabled))
{
#$Status = " [Disabled]"
}
}
$count +=1
$locadmins+="$($user1)$($Status)"
Write-Output "$($user1)$($Status)"
# is this an AzureAD Admin that's enabled?
if (($domainname -eq "AzureAD") -and (-not ($locadmin_info.Enabled)))
{
#$azadmins += $user1
}
}
}
Function RegGet ($keymain, $keypath, $keyname)
{
#########
## $ver=RegGet "HKCR" "Word.Application\CurVer"
## $ver=RegGet "HKLM" "System\CurrentControlSet\Control\Terminal Server" "fDenyTSConnections"
#########
$result = ""
Switch ($keymain)
{
"HKLM" {$RegGetregKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($keypath, $false)}
"HKCU" {$RegGetregKey = [Microsoft.Win32.Registry]::CurrentUser.OpenSubKey($keypath, $false)}
"HKCR" {$RegGetregKey = [Microsoft.Win32.Registry]::ClassesRoot.OpenSubKey($keypath, $false)}
}
if ($RegGetregKey)
{
$result=$RegGetregKey.GetValue($keyname, $null, "DoNotExpandEnvironmentNames")
}
$result
}
#endregion Functions
$scriptFullname = $PSCommandPath ; if (!($scriptFullname)) {$scriptFullname =$MyInvocation.InvocationName}
################################ Main Code Area
$scriptName = "PC Info.ps1"
#$scriptVer = "v2023-11-20"
$scriptVer = "v"+(Get-Item $scriptFullname).LastWriteTime.ToString("yyyy-MM-dd")
################################
Write-Host "$($scriptName) $($scriptVer)" -ForegroundColor Yellow
Write-Host " Gathering registry info..."
## Read Teamviewer ID from registry
$tvid = RegGet "HKLM" "SOFTWARE\WOW6432Node\TeamViewer" "ClientID"
If ($tvid -eq "") {$tvid = RegGet "HKLM" "SOFTWARE\TeamViewer" "ClientID"}
$tvaccnt = RegGet "HKLM" "SOFTWARE\WOW6432Node\TeamViewer" "OwningManagerAccountName"
If ($tvaccnt -eq "") {$tvaccnt = RegGet "HKLM" "SOFTWARE\TeamViewer" "OwningManagerAccountName"}
$TeamviewerID = [string]$tvid
If (($null -ne $tvaccnt) -and ($tvaccnt -ne "")) {$TeamviewerID +=" ($($tvaccnt))"}
Write-Host " Gathering network info..."
# Networks
$networks=@()
$NetConnectionProfiles = Get-NetConnectionProfile | Sort-Object InterfaceIndex
ForEach ($NetConnectionProfile in $NetConnectionProfiles)
{
$NetIPAddress = Get-NetIPAddress -InterfaceIndex $NetConnectionProfile.InterfaceIndex -AddressFamily IPV4
$NetAdapter = Get-NetAdapter -InterfaceIndex $NetConnectionProfile.InterfaceIndex
#
$network = $NetIPAddress.IPAddress
$network += " $($NetConnectionProfile.InterfaceAlias) $($NetConnectionProfile.Name) ($($NetConnectionProfile.NetworkCategory))"
$network += " [$($NetAdapter.MacAddress)]"
#
$networks += $network
}
Write-Host " Gathering disk info..."
# Disks
$disks=@()
$Getdisks = Get-disk | Sort-Object Number
ForEach ($Getdisk in $Getdisks)
{
$disk = $Getdisk.FriendlyName
$disk += " " + ($Getdisk.Size / 1GB).ToString("0.# GB")+""
#
$volumes = $Getdisk | Get-Partition | Get-Volume | Where-Object DriveLetter -ne $null
ForEach ($volume in $volumes)
{
$disk += " [" + $volume.DriveLetter.ToString().ToUpper() + ": "
$disk += ($volume.SizeRemaining / 1GB).ToString("#.# GB")+" free of "
$disk += ($volume.Size / 1GB).ToString("#.# GB")+"]"
}
$disks += $disk
}
Write-Host " Gathering public ip info..."
# Public IP
$PublicIP_Info = Invoke-RestMethod http://ipinfo.io/json -UseBasicParsing
Write-Host " Gathering fast boot and notification info..."
# Windows settings
[string]$reg_hiberbootenabled = RegGet "HKLM" "SYSTEM\CurrentControlSet\Control\Session Manager\Power" "HiberbootEnabled"
[string]$reg_toastenabled = RegGet "HKCU" "SOFTWARE\Microsoft\Windows\CurrentVersion\PushNotifications" "ToastEnabled"
if ($reg_hiberbootenabled -eq "") {$reg_hiberbootenabled = "(blank)"}
if ($reg_toastenabled -eq "") {$reg_toastenabled = "(blank)"}
##
if ($reg_hiberbootenabled -eq "1") {$reg_hiberbootenabled_desc="Warning: Fast Boot is enabled"} else {$reg_hiberbootenabled_desc="OK: Fast Boot is disabled (shutdown same as restart)"}
if ($reg_toastenabled -eq "0") {$reg_toastenabled_desc="Warning: System notifications are disabled for current user"} else {$reg_toastenabled_desc="OK: System notifications are enabled for current user"}
Write-Host " Gathering last boot info..."
# PC boot
$pc = Get-WmiObject win32_operatingsystem | Select-Object CSName, @{N="LastBootUpTime";E={[System.Management.ManagementDateTimeConverter]::ToDateTime($_.LastBootUpTime)}}
$days_fromstartup = ((Get-Date)-($pc.LastBootUpTime)).TotalDays
Write-Host " Gathering local admin info..."
# Local Admins
$localuser = "$($env:userdomain)\$($env:username)"
$localadmins = LocalAdmins
$IsLocalAdmin = if (IsLocalAdmin) {"YES"} else {"NO"}
$IsAdmin = if (IsAdmin) {"YES"} else {"NO"}
Write-Host " Gathering azure ad info..."
# Azure Info
$dsregcmd = dsregcmd /status | Where-Object { $_ -match ' : ' } | ForEach-Object { $_.Trim() } | ConvertFrom-String -PropertyNames 'Name','Value' -Delimiter ' : '
Write-Host " Gathering computer info..."
# PC Info
$computerInfo = Get-ComputerInfo
if ($computerInfo.BiosSerialNumber)
{$sn = $computerInfo.BiosSerialNumber}
else
{$sn = $computerInfo.BiosSeralNumber} # oddly was misspelled up to recent versions of windows
Write-Host " Gathering display info..."
# Display
$dispctrls = GetDisplayControllers
$dispmons = GetDisplayMonitors
$dispmonres = GetDisplayMonitorResolutions
$displayinfo = "$($dispctrls -join ", "):$($dispmons -join ", "):$($dispmonres -join ", ")"
Write-Host " Gathering winget info..."
# winget
Try {$wingetver = & winget -v}
Catch {$wingetver = "(none)"}
Write-Host " Gathering bitlocker info..."
# BitLocker
$OSDrive = $env:SystemDrive
# $bitlocker = Get-BitLockerVolume -MountPoint $OSDrive # requires elevation
$bitlocker = (New-Object -ComObject Shell.Application).NameSpace($OSDrive).Self.ExtendedProperty('System.Volume.BitLockerProtection')
if ($bitlocker -eq 1) {$bitlockerstatus = "Encrypted"}
elseif ($bitlocker -eq 3) {$bitlockerstatus = "Encryption in progress"}
else {$bitlockerstatus = "Not encrypted"}
$bitlockerstatus += " $($OSDrive) ($($bitlocker))"
Write-Host "Done gathering info."
####
$objProps = [ordered]@{
Computername = $computerInfo.CsName
ComputerSN = $sn
OSInfo = "$($computerInfo.OsName) ($($computerInfo.OSDisplayVersion)) v$($computerInfo.OsVersion) $($computerInfo.OsArchitecture)"
Model = "$($computerInfo.CsManufacturer) $($computerInfo.CsModel)"
CPU = $computerinfo.CsProcessors[0].Name + " (" + $computerinfo.CsProcessors[0].NumberOfCores + "C)"
Memory = ($computerInfo.CsTotalPhysicalMemory / 1GB).ToString("#.# GB")
Disks = $Disks -join ", "
Bitlocker = $bitlockerstatus
Display = $displayinfo
Networks = $networks -join ", "
PublicIP = $PublicIP_Info.ip
PublicIP_Loc = "$($PublicIP_Info.city) $($PublicIP_Info.region) $($PublicIP_Info.postal) $($PublicIP_Info.country) [$($PublicIP_Info.org)]"
TeamviewerID = $TeamviewerID
Domain = $env:userdomain
Winget = $wingetver
User = $localuser
LocalAdmins = $localadmins -join ", "
IsLocalAdmin = $IsLocalAdmin
IsAdminNow = $IsAdmin
#AZADAccount = ($dsregcmd | Where-Object -Property Name -eq "Executing Account Name").Value
AZADJoined = ($dsregcmd | Where-Object -Property Name -eq "AzureAdJoined").Value
DeviceId = ($dsregcmd | Where-Object -Property Name -eq "DeviceId").Value
TenantName = ($dsregcmd | Where-Object -Property Name -eq "TenantName").Value
TenantId = ($dsregcmd | Where-Object -Property Name -eq "TenantId").Value
Shutdown = "$($reg_hiberbootenabled), $($reg_hiberbootenabled_desc)"
Notifications = "$($reg_toastenabled), $($reg_toastenabled_desc)"
LastBootUpTime= $pc.LastBootUpTime.tostring("g")
LastBootDaysAgo= "$($days_fromstartup.tostring("0.#")) days ago"
}
$infoObject = New-Object -TypeName psobject -Property $objProps
$out_info = ($infoObject | Out-String).Trim()
$out_separator = "-----------------------------------------------------------------------------"
$out_header = "$($scriptName) $($scriptVer) Computer:$($env:computername) User:$($env:username) PSver:$($PSVersionTable.PSVersion.Major).$($PSVersionTable.PSVersion.Minor)"
$out_lines=@()
$out_lines+=$out_separator
$out_lines+=$out_header
$out_lines+=$out_separator
$out_lines+=$out_info
$out_lines+=$out_separator
$out_lines | Write-Host
### Drop a report in the downloads folder
$folder_downloads = (New-Object -ComObject Shell.Application).NameSpace('shell:Downloads').Self.Path
$date = get-date -format "yyyy-MM-dd_HH-mm-ss"
$file = "$($folder_downloads)\PC Info $($date).txt"
# write file
$out_lines | Out-File $file
#################################################
Read-Host -Prompt "Report saved to Downloads folder. Press Enter to exit and open that file."
# open file
Invoke-Item $file