Systeminfo.psm1
<#
.SYNOPSIS Very fast displays system information on a local or remote computer. .DESCRIPTION The function uses WMI to collect information related to the characteristics of the computer The function uses multithreading. Multithreading is implemented through powershell runspace and PsJob The function allows you to quickly get the system information of a large number of computers on the network After executing, two variables are created: $Result-contains successful queries, $ErrorResult-contains computers that have errors. .PARAMETER ProcessFor This parameter determines the maximum number of computers for which WMI operations that can be executed simultaneously. By default, the value of this parameter is 50. .PARAMETER JobTimeout Specifies the amount of time that the function waits for a response from the wmi job or runspace job. By default, the value of this parameter is 120 seconds. .PARAMETER Protocol Defines the connection protocol to remote machine By default DCOM protocol .PARAMETER AppendToResult Adds the output to the $Result global variable. Without this parameter, $Result global variable replaces. .PARAMETER Credential Specifies a user account that has permission to perform this action. The default is the current user. Type a user n ame, such as "User01", "Domain01\User01", or User@domain01.com. Or, enter a PSCredential object, such as an object t hat is returned by the Get-Credential cmdlet. When you type a user name, you are prompted for a password. .EXAMPLE Get-SystemInfo This command get the system information on the local computer. .EXAMPLE Get-SystemInfo -Computername comp1,comp2,comp3 This command receives system information from computers comp1, comp2, comp3. By default, the current account must be a member of the Administrators group on the remote computer. .EXAMPLE 1..254 | foreach {"192.168.1.$_"} | Get-SystemInfo -Properties OsCaption,OSArchitecture,OsInstallDate -Credential Domain01\administrator01 | Out-GridView Get OsCaption, OSArchitecture, OsInstallDate from the computers that are in the 192.168.1.0/24 network and sends them to a grid view window. This command uses the Credential parameter. The value of the Credential parameter is a user account name. The user is prompted for a password. .EXAMPLE Get-ADComputer -Filter * | Get-SystemInfo -Cpu -Motherboard -Memory -Properties OsVersion,OsProductKey -ProcessFor 100 -JobTimeOut 30 Get CPU, Motherboard, Memory and OsVersion, OsProductKey information from all domain computers. The module activedirectory must be installed and loaded. This command uses -ProcessFor and JobTimeOut parameter. .EXAMPLE Get-ADComputer -Filter * | Get-SystemInfo -Protocol WSMAN This command gets system information from all domain computers. Wsman protocol is used for connection If errors occur, such as timeout expired or other errors. After some time, you can repeat the command for computers that have had errors.To do this, you need to use the variable $ErrorResult and -AppendToResult parameter to add the result to a variable $Result. PS C:\>$ErrorResult | Get-SystemInfo -Protocol WSMAN -AppendToResult .EXAMPLE Get-Content -Path C:\Computers.txt | Get-SystemInfo -Properties MemoryTotal,OsLoggedInUser -WarningAction SilentlyContinue | Where-Object {$_.memorytotal -lt 1.5gb} This command gets computers that have a RAM size less than 1.5 gb. List of computers is taken from the file C:\Computers.txt. This command use parameter -WarningAction SilentlyContinue to ignore warning. .EXAMPLE Get-Content -Path C:\Computers.txt | Get-SystemInfo -Properties OsLoggedInUser,HddSmart -Protocol WSMAN | Where-Object {$_.hddsmart.smartstatus -Match "Critical" -or $_.hddsmart.smartstatus -Match "Warning"} This command gets computers that have hard disk problems. List of computers is taken from the file C:\Computers.txt .EXAMPLE Get-AdComputer -filter * | Get-SystemInfo -Properties OsKernelPowerFailCount,OsBSod,HDDSmart -Protocol WSMAN | Select-Object -Property @("ComputerName","OsKernelPowerFailCount",@{Name='LastBSoD';Expression={$_.OsBSoD.LastBSoD}},@{Name='BSoDCount';Expression={$_.OsBSoD.BSoDCount}},@{Name='HddModel';Expression={$_.HDDSmart.Model}},@{Name='SmartStatus';Expression={$_.HDDSmart.SmartStatus}},@{Name='ErrorRecordsFromEventlog';Expression={$_.HDDSmart.ErrorRecordsFromEventlog}}) | Out-GridView This command can be used to find disk related problems. The module activedirectory must be installed and loaded. .EXAMPLE Get-ADComputer -Filter * | Get-SystemInfo -Properties OsUpTime -JobTimeOut 30 | Where-Object {$_.OsUpTime -gt $(New-TimeSpan -Days 1)} This command gets computers which have uptime is more than 1 day. The module activedirectory must be installed and loaded .EXAMPLE Get-ADComputer -filter * | Get-SystemInfo -SoftwareList -JobTimeOut 240 | foreach {$_.SoftwareList} | Where-Object {$_.AppName -match "Google Chrome"} | Out-GridView This command gets computers with google chrome browser installed. The module activedirectory must be installed and loaded .EXAMPLE $Computers=Get-Content -Path C:\Computers.txt Get-SystemInfo -Computername $Computers | ConvertTo-Html -Head "SystemInformation" | Out-File -FilePath C:\report.html This command create html report .NOTES Author: SAGSA https://github.com/SAGSA/SystemInfo Requires: Powershell 2.0 #> function Get-SystemInfo { [CmdletBinding()] param( [parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true,Position=0)] [Alias('CN','Computername','DnsHostname','PsComputerName')] [string[]]$Name=$Env:COMPUTERNAME, [switch]$OsInfo, [switch]$Cpu, [switch]$Motherboard, [switch]$Memory, [switch]$HDD, [switch]$Video, [switch]$Monitor, [switch]$NetworkAdapter, [switch]$PrinterInfo, [switch]$UsbDevices, [switch]$SoftwareList, [switch]$CheckVulnerabilities, [switch]$DefaultInfo, [System.Management.Automation.Remoting.PSSessionOption]$PSSessionOption, $Credential, [ValidateSet("Dcom","Wsman")] $Protocol="Dcom", [Alias("ThrottleLimit")] [ValidateRange(1,500)] [int]$ProcessFor=50, [ValidateRange(1,500)] [int]$MaxWmiJob=20, [Alias("Timeout")] [ValidateRange(1,6000)] [int]$JobTimeOut=120, [switch]$AppendToResult, [ValidateSet("*", "OsVersion","OsBuild","OSArchitecture","OsCaption","OsGuid","OsLastUpdateDaysAgo","OsInstallDate","OsUpTime","OsLoggedInUser","OsTimeZone","OsProductKey","OsTenLatestHotfix","OsUpdateAgentVersion","OSRebootRequired","OsAdministrators","OsActivationStatus", "OsProfileList","OsSRPSettings","OsSrpLog","OsMstscVersion","OsPowerPlan","OsBSoD","LastInteractiveUser","SerialNumber","ProductNumber","ADSiteName","MsOfficeInfo","UserProxySettings","NetFolderShortcuts","NetMappedDrives","PsVersion","MemoryTotal","MemoryFree","MemoryModules","MemoryModInsCount","BiosInfo", "MemoryMaxIns","MemorySlots","ECCType","MemoryAvailable","Motherboard","MotherboardModel","DeviceModel","Cdrom","CdromMediatype","HddDevices","HDDSmart", "HddSmartStatus","HddPartitions","HddVolumes","VolumeQuotaSetting","VolumeQuotaList","VolumeShadowCopy","VolumeShadowStorage","VideoModel","VideoRam","VideoProcessor","CPUName","CPUDescription","CPUSocket","MaxClockSpeed","CPUCores","CPULogicalCore","CPULoad","MonitorManuf", "MonitorPCode","MonitorSN","MonitorName","MonitorYear","NetPhysAdapCount","NetworkAdapters","NetworkAdaptersPowMan","Printers","IsPrintServer","UsbConPrOnline","UsbDevices","SoftwareList","MeltdownSpectreStatus","EternalBlueStatus","AntivirusStatus","SkypeInfo","GoogleChromeInfo","SysmonInfo","Software1cInfo","Server1cInfo","OsKernelPowerFailCount","MseLastUpdateDate","BatteryInfo")] [string[]]$Properties ) begin { $TestAdmin = New-Object Security.Principal.WindowsPrincipal $([Security.Principal.WindowsIdentity]::GetCurrent()) $IsAdmin=$TestAdmin.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator) Write-Verbose "IsAdmin $IsAdmin" $CurrentExecutionPolicy=Get-ExecutionPolicy $ExecutionPolicyChanged=$false $RequiredExecutionPolicy="Unrestricted","RemoteSigned" if (!($RequiredExecutionPolicy -eq $CurrentExecutionPolicy)) { Write-Verbose "Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force" try { Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force -Confirm:$false if ($?) { $ExecutionPolicyChanged=$true } else { Write-Error "Formatting objects does not work. Run the command Set-ExecutionPolicy -ExecutionPolicy RemoteSigned and retry now" -ErrorAction Stop } } catch { Write-Error "RequiredExecutionPolicy $RequiredExecutionPolicy" -ErrorAction Stop } } #LoadFunctions ##################################################################################################### $FunctionFolderName="Function" $LoadScripts=@( "Config\functionconfig.ps1", "$FunctionFolderName\ParseParam.ps1", "$FunctionFolderName\CreateResult.ps1", "$FunctionFolderName\FormatObject.ps1", "$FunctionFolderName\GetHddSmart.ps1", "$FunctionFolderName\wmi.ps1", "$FunctionFolderName\Registry.ps1", "$FunctionFolderName\CreateErrorObject.ps1", "$FunctionFolderName\PsJob.ps1", "$FunctionFolderName\RunspaceJob.ps1", "$FunctionFolderName\GetUserProfile.ps1", "$FunctionFolderName\GetSmBiosStruct.ps1", "$FunctionFolderName\GetInstalledSoftware.ps1" ) $LoadScripts | foreach { .(Join-Path -Path $PSScriptRoot -ChildPath $_) if(!$?) { break } } ##################################################################################################### $BeginFunction=get-date if ($PSCmdlet.MyInvocation.BoundParameters['Credential']) { if (!($Credential.gettype().name -eq "PSCredential")) { $Credential=Get-Credential $Credential } } if (!($PSCmdlet.MyInvocation.BoundParameters['PSSessionOption']) -and $Protocol -eq "Wsman") { #Default PSSessionOption Write-Verbose "New-PSSessionOption -NoMachineProfile" $PSSessionOption=New-PSSessionOption -NoMachineProfile } #Clear Old Job Write-Verbose "Clear old Job" Get-Job | Where-Object {$_.state -ne "Running"} | Remove-Job -Force #Collection all Properties [string[]]$AllPropertiesSwitch+=$PSCmdlet.MyInvocation.BoundParameters.keys | foreach { if ($PSCmdlet.MyInvocation.BoundParameters[$_].ispresent -and !($ExcludeParam -eq $_)) { $SwitchConfig[$_] } } if ($AllPropertiesSwitch -eq $Null -and $Properties -eq $null) { $AllPropertiesSwitch=$DefaultInfoConfig } $AllProperties+=$AllPropertiesSwitch+$Properties $AllProperties = $AllProperties | Select-Object -Unique if ($AllProperties -match "\*") { Write-Verbose "Property: $($FunctionConfig.Keys)" $AllProperties=$FunctionConfig.Keys -ne "RegistryValue" } else { Write-Verbose "Property: $AllProperties" } #Parse FunctionConfig $PropertyParams=$AllProperties | ParseFunctionConfig -FunctionConfig $FunctionConfig -Protocol $Protocol $Propertyparams.Keys | foreach {$PropertyParams[$_] | Where-Object {$_.script}} | foreach { $ScriptTmp=$_ $ScriptPath=Join-Path -Path $PSScriptRoot -ChildPath "scripts\$($ScriptTmp.script)" $Script=Get-Content -Path $ScriptPath -ErrorAction Stop | Out-String if ((Split-Path -Path $ScriptPath) -match ".+\\(.+)") { $RootFoolder=$Matches[1] $FunctionName="FunctInf"+$RootFoolder+$((Split-Path -Path $ScriptPath -Leaf) -replace "\.ps1","") } else { Write-Error "$FunctionProperty incorrect path" -ErrorAction Stop } [void](New-Item -Path function: -Name $FunctionName -Value $Script -ErrorAction Stop) $ScriptTmp | Add-Member -MemberType NoteProperty -Name Function -Value $FunctionName } #Create wmi param $WmiParamArray=CreateWmiObject -PropertyParams $PropertyParams -ManualNamespace $ManualNamespace $computers=@() $MainJobs = New-Object System.Collections.ArrayList $GetWmicompletedForComputers = New-Object System.Collections.ArrayList $HashtableRunspace=@() $Global:ErrorResult=@() $UpdateFormatData=$true if ($PSBoundParameters["AppendToResult"].IsPresent) { if (!(Get-Variable -Name Result -Scope Global)) { $Global:Result=@() } elseif((Get-Variable -Name Result -Scope Global -ValueOnly).count -eq $null) { $OldRes=$Global:Result $Global:Result=@() $Global:Result+=$OldRes } } else { $Global:Result=@() } [ScriptBlock]$SbLocalHost= { $Protocol="Wsman" Write-Verbose "$ComputerName Protocol $Protocol" $HashtableWMi=@{} $WmiParamArray | foreach { $WmiParam=$_ if ($WmiParam.Name) { if (!($HashtableWMi.ContainsKey($($WmiParam.Name)))) { #$HashtableWMi[$($WmiParam.Name)] $HashtableWMi.Add($WmiParam.Name,$null) } } } $jobs = New-Object System.Collections.ArrayList StartWmiJob -computername $Computername -WmiParamArray $WmiParamArray do { GetWmiJob } while($jobs.Count -ne 0) CreateResult } $CountComputers=0 [Array]$ExportFunctionsName="StartWmiJob","GetWmiJob","CreateResult" [Array]$PropertyReqHddSmartFunctions="HddDevices","HddSmartStatus","HddSmart" [Array]$PropertyReqGetUserProfileFunctions="NetFolderShortcuts","OsProfileList","NetMappedDrives" [Array]$PropertyReqGetSmBiosStructFunctions="MemoryModules" [Array]$PropertyReqGetInstalledSoftware="SoftwareList","SkypeInfo","GoogleChromeInfo","Software1cInfo" #$PropertyReqRegistryFunctions="OsProductKey","SoftwareList","MeltdownSpectreStatus","EternalBlueStatus" $WmiParamArray | foreach { if ($PropertyReqHddSmartFunctions -eq $_.property) { if (!($ExportFunctionsName -eq "GetHddSmart")) { $ExportFunctionsName+="GetHddSmart" } } if ($PropertyReqGetUserProfileFunctions -eq $_.property) { if (!($ExportFunctionsName -eq "GetUserProfile")) { $ExportFunctionsName+="GetUserProfile" } } if ($PropertyReqGetSmBiosStructFunctions -eq $_.property) { if (!($ExportFunctionsName -eq "GetSmBiosStruct")) { $ExportFunctionsName+="GetSmBiosStruct" } } if ($PropertyReqGetInstalledSoftware -eq $_.property) { if (!($ExportFunctionsName -eq "GetInstalledSoftware")) { $ExportFunctionsName+="GetInstalledSoftware" } } if ($_.class -eq "StdRegProv") { if (!($ExportFunctionsName -eq "RegGetValue")) { $ExportFunctionsName+="RegGetValue","RegEnumKey" } } } Write-Verbose "$protocol protocol" if ($Protocol -eq "DCOM" -and $PSCmdlet.MyInvocation.InvocationName -ne $PSCmdlet.MyInvocation.line) { $ExportFunctionsName+="StartWmi" #$RunspaceImportVariables="WmiParamArray","Credential","Protocol" $SessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault() Get-Command -CommandType Function -Name $ExportFunctionsName | foreach { $SessionStateFunction = New-Object System.Management.Automation.Runspaces.SessionStateFunctionEntry -ArgumentList $_.name, $_.Definition Write-Verbose "Add Function $($_.name)" $SessionState.Commands.Add($SessionStateFunction) } Get-Command -CommandType Function -Name FunctInf* | foreach { $SessionStateFunction = New-Object System.Management.Automation.Runspaces.SessionStateFunctionEntry -ArgumentList $_.name, $_.Definition Write-Verbose "Add script Function $($_.name)" $SessionState.Commands.Add($SessionStateFunction) } $SessionStateVariables=New-Object System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList "WmiParamArray", $WmiParamArray, "WmiParamArray" $SessionState.Variables.Add($SessionStateVariables) $SessionStateVariables=New-Object System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList "Credential", $Credential, "Credential" $SessionState.Variables.Add($SessionStateVariables) $SessionStateVariables=New-Object System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList "VerbosePreference", $VerbosePreference, "VerbosePreference" $SessionState.Variables.Add($SessionStateVariables) $SessionStateVariables=New-Object System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList "Protocol", $Protocol, "Protocol" $SessionState.Variables.Add($SessionStateVariables) $RunspacePool = [runspacefactory]::CreateRunspacePool(1,$ProcessFor,$SessionState,$Host) Write-Verbose "Open Runspace" $RunspacePool.Open() } else { $VerboseStatus=$VerbosePreference $ExportFunctions=@() $ExportFunctionsName | foreach {$ExportFunctions+=Get-ChildItem -Path function:$_} $ExportScriptFunction=@() $ExportScriptFunction=Get-ChildItem -Path function:\FunctInf* [Array]$ExportVariablesName="WmiParamArray","MaxWmiJob","VerboseStatus","Protocol" $ExportVariables=@() $ExportVariablesName | foreach {$ExportVariables+=Get-Variable -Name $_} $HashtableParam=@{ ImportFunctions=$ExportFunctions ImportScriptFunction=$ExportScriptFunction ImportVariables=$ExportVariables } } } process { $computers=@() if ($Name -ne $null) { $computers+=$Name } $computers| foreach { $ComputerName=$_ $CountComputers++ $AllProperties | foreach { if (!$IsAdmin) { if ($LocalComputer -eq $ComputerName) { if ($AdminRequired -eq $_) { Write-Warning "$ComputerName Information may be incomplete. The $_ property requires administrator privileges. Close powershell and run as administrator" } } } } if ($LocalComputer -eq $ComputerName) { Write-Verbose "$Computername running local" &$SbLocalHost | OutResult } elseif ($Protocol -eq "Wsman") { #Protocol WSMAN if ($MainJobs.count -ge $ProcessFor) { do{ $repeat=$true GetPsJob | OutResult if ($MainJobs.Count -lt $ProcessFor) { $repeat=$false } else { Start-Sleep -Milliseconds 20 } }while($repeat) } $NewJob=StartPsJob -ComputerName $ComputerName -ScriptBlock $InvokeScriptBlock -ArgumentList $HashtableParam,$ComputerName -Credential $Credential -PSSessionOption $PSSessionOption if ($NewJob) { [void]$MainJobs.Add($NewJob) } } else { #Protocol DCOM if ($MainJobs.count -ge $ProcessFor) { do{ $repeat=$true GetRunspaceJob | OutResult if ($MainJobs.Count -lt $ProcessFor) { $repeat=$false } else { Start-Sleep -Milliseconds 20 } }while($repeat) } Write-Verbose "$Computername StartRunspaceJob" $RunspaceJob=StartRunspaceJob -Computername $Computername -RunspacePool $RunspacePool if ($?) { [void]$MainJobs.Add($RunspaceJob) } } #End Foreach } } end { if ($MainJobs.Count -eq 1 -and $LocalComputer -eq $MainJobs[0].location) { do { GetPsJob | OutResult } while($MainJobs.Count -ne 0) } elseif ($Protocol -eq "Wsman" -and $MainJobs.Count -ne 0) { do { GetPsJob | OutResult } while($MainJobs.Count -ne 0) } elseif ($mainjobs.Count -ne 0) { do { GetRunspaceJob | OutResult } while($MainJobs.Count -ne 0) [Scriptblock]$CloseRunspacePool= { param($RunspacePool) $RunspacePool.Dispose() $RunspacePool.Close() } Write-Verbose "RunspacePool close" $PowerShell = [powershell]::Create() [void]$PowerShell.AddScript($CloseRunspacePool) [void]$PowerShell.AddParameter("RunspacePool",$RunspacePool) $State = $PowerShell.BeginInvoke() } $Global:ErrorResult=$Global:ErrorResult | Sort-Object -Property Warning if ($Global:ErrorResult -eq $null) { $ErrResCount=0 } elseif ($Global:ErrorResult.count -eq $null) { $ErrResCount=1 } else { $ErrResCount=$Global:ErrorResult.count } $ResultCount=$Global:Result.count if ($Global:Result.Count -eq 1) { $Global:Result=$Global:Result | foreach {$_} } if ($ExecutionPolicyChanged) { Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy $CurrentExecutionPolicy -Force -Confirm:$false -ErrorAction SilentlyContinue } #Write-Verbose "Clear all failed wmi job" #Get-Job | Where-Object {$_.State -eq "Failed"} | Remove-Job -Force $RunnningTime=(New-TimeSpan -Start $BeginFunction).TotalSeconds if ($CountComputers -gt 1) { Write-Verbose "Function running $RunnningTime seconds" -Verbose Write-Verbose "Speed $([math]::Round($($CountComputers/$RunnningTime),2)) cps" -Verbose Write-Verbose "Total Computers $CountComputers" -Verbose Write-Verbose "Success $ResultCount" -Verbose Write-Verbose "Errors $ErrResCount" -Verbose } #End Function } } |