PowerShell interrogate a remote system - powershell

I have a function that I wrote that interrogates my local system. Just gathering whatever information I can get in a useful format. So I was wondering about a function that could interrogate other systems in this kind of way. function sys-remote <$ip-or-hostname> With that it could then try and return as much information about that system as it can. It's just an idea really, and I guess a number of points would be useful:
• With an IP address, how can we resolve the hostname in the most PowerShell'ish way?
• Whether a hostname of IP address is provided, can we resolve as much information as possible. i.e. MAC address, hostname, IP (and possibly other IP addresses if these can be visible to us)?
• Can we recover shared drives on that system so can see a list of possible shares to connect to.
• What about system information, would that always require WinRM, or can WMI or CIM suffice for most of the things in the below?
• Maybe return also a comma-separate list of whatever ports are open on that remote system if possible?
• What if the remote system is Linux. How much of the above can we reasonably obtain from a Linux system that we interrogate remotely from our Windows system (I guess that WinRM and WMI are out, but maybe CIM is still possible?)?
In general, it would be really useful to return a dump of information like this from a diagnostic point of view as would give a ton of information about a system to work from. Anything like the above (or indeed any other useful things to check for that I've not thought of here) would be really appreciated.
function sys {
$System = get-wmiobject -class "Win32_ComputerSystem"
$Mem = [math]::Ceiling($System.TotalPhysicalMemory / 1024 / 1024 / 1024)
$wmi = gwmi -class Win32_OperatingSystem -computer "."
$LBTime = $wmi.ConvertToDateTime($wmi.Lastbootuptime)
[TimeSpan]$uptime = New-TimeSpan $LBTime $(get-date)
$s = "" ; if ($uptime.Days -ne 1) {$s = "s"}
$uptime_string = "$($uptime.days) day$s $($uptime.hours) hr $($uptime.minutes) min $($uptime.seconds) sec"
$job_cpu = Start-Job -ScriptBlock { (Get-WmiObject -Class Win32_Processor).Name }
$job_cpu_cores = Start-Job -ScriptBlock { (Get-WmiObject -Class Win32_Processor).NumberOfCores }
$job_cpu_logical = Start-Job -ScriptBlock { (Get-WmiObject -Class Win32_Processor).NumberOfLogicalProcessors }
""
"Hostname: $($System.Name)"
"Domain: $($System.Domain)"
"PrimaryOwner: $($System.PrimaryOwnerName)"
"Make/Model: $($System.Manufacturer) ($($System.Model))" # "ComputerModel: $((Get-WmiObject -Class:Win32_ComputerSystem).Model)"
"SerialNumber: $((Get-WmiObject -Class:Win32_BIOS).SerialNumber)"
"PowerShell: $($PSVersionTable.PSVersion)"
"Windows Version: $($PSVersionTable.BuildVersion), Windows ReleaseId: $((Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name 'ReleaseId').ReleaseId)"
"Display Card: $((Get-WmiObject -Class:Win32_VideoController).Name)"
"Display Driver: $((Get-WmiObject -Class:Win32_VideoController).DriverVersion), Description: $((Get-WmiObject -Class:Win32_VideoController).VideoModeDescription)"
"Last Boot Time: $([Management.ManagementDateTimeConverter]::ToDateTime((Get-WmiObject Win32_OperatingSystem | select 'LastBootUpTime').LastBootUpTime)), Uptime: $uptime_string"
$IPDefaultAddress = #(Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object {$_.DefaultIpGateway})[0].IPAddress[0]
$IPDefaultGateway = #(Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object {$_.DefaultIpGateway})[0].DefaultIPGateway[0]
"Default IP: $IPDefaultAddress / $IPDefaultGateway"
Get-Netipaddress | where AddressFamily -eq IPv4 | select IPAddress,InterfaceIndex,InterfaceAlias | sort InterfaceIndex
""
Wait-Job $job_cpu | Out-Null ; $job_cpu_out = Receive-Job -Job $job_cpu
Wait-Job $job_cpu_cores | Out-Null ; $job_cpu_cores_out = Receive-Job -Job $job_cpu_cores
Wait-Job $job_cpu_logical | Out-Null ; $job_cpu_logical_out = Receive-Job -Job $job_cpu_logical
"CPU: $job_cpu_out"
"CPU Cores: $job_cpu_cores_out, CPU Logical Cores: $job_cpu_logical_out"
# Get-PSDrive | sort -Descending Free | Format-Table
gwmi win32_logicaldisk | Format-Table DeviceId, VolumeName, #{n="Size(GB)";e={[math]::Round($_.Size/1GB,2)}},#{n="Free(GB)";e={[math]::Round($_.FreeSpace/1GB,2)}}
gwmi win32_winsat | select-object CPUScore,D3DScore,DiskScore,GraphicsScore,MemoryScore,WinSPRLevel | ft # removed ,WinSATAssessmentState
get-WmiObject -class Win32_Share | ft
}

No reason to do this sort of thing from scratch. There are many existing scripts for what you are doing. Via the Microsoft powershellgallery.com.
PowerShell Script For Desktop Inventory Basic script to collect
desktop inventory.
PowerShell Hardware Inventory Script Scenario:PowerShell hardware
Inventory Script. Have you ever wanted to have an inventory without the
hassle of going to each finding the information needed to fill the
information for your inventory? It is important to keep your inventory
up to date. Every time there is a change y
DownloadGet-Inventory.ps1
You can just take your script and use Invoke-Command (Runs commands on local and remote computers.) in a PowerShell remote session to get remote computer info.

Related

Powershell variable not being populated

Here's the simple script:
$groups = Get-WMIObject -Class Win32_GroupUser -ComputerName $server | Select-object #{N="Group";E={($_.PartComponent -split "Name=")[1].Replace('"','')}}
$groups
However, $groups is null!
I've checked the interwebs and cannot find a solution.
I'm sure there's a simple answer...
Query is syntactically correct. Check if you are storing the correct value in the $server parameter and that your WMI service is running.
Nothing wrong with what you have here, as it pulls the data when I test this.
Note I am using my localhost, not a remote system here.
(
$groups = Get-WMIObject -Class Win32_GroupUser -ComputerName $env:COMPUTERNAME `
| Select-object #{N="Group";E={($_.PartComponent -split "Name=")[1].Replace('"','')}}
)
Group
-----
postanote
...
IUSR
...
SYSTEM
...
INTERACTIVE
Authenticated Users
...
DefaultAccount
Guest
Administrator
...
SYSTEM
...
$groups.Count
27
And fine on a remote system.
(
$groups = Get-WMIObject -Class Win32_GroupUser -ComputerName 'ws01' `
| Select-object #{N="Group";E={($_.PartComponent -split "Name=")[1].Replace('"','')}}
)
Group
-----
Administrator
Domain Admins
...
Guest
SYSTEM
...
INTERACTIVE
Authenticated Users
Domain Users
SYSTEM
$groups.Count
18
So, something environmental in your environment, is the catch 22 for you.
Run this on your localhost host and see if you can get anything back from your targets.
Test-WSMan -ComputerName ws01
wsmid : http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd
ProtocolVersion : http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd
ProductVendor : Microsoft Corporation
ProductVersion : OS: 0.0.0 SP: 0.0 Stack: 3.0

Convert a .bat to .ps1 to find removable USB drives on a Windows 10 workstation [duplicate]

This question already has answers here:
Get the drive letter of USB drive in PowerShell
(5 answers)
Closed 5 years ago.
I found the below code to search a Window 7 workstation for any USB Removable Drive (a memory stick really) on the internet years ago. I still don't fully understand the "/F", "tokens=1*", "tokens=3", "in (fsutil fsinfo drives)" and "in (fsutil fsinfo drivetype %%c)".
Now I have a new Windows 10 workstation and need to convert to PowerShell 5. Can anyone help me get started on how to convert this .bat to .ps1?
I am on...
Major 5
Minor 1
Build 16299
Revision 98
#echo off
echo Workstation backup
:tryAgain
set isUSBfound=false
for /F "tokens=1*" %%a in ('fsutil fsinfo drives') do (
for %%c in (%%b) do (
for /F "tokens=3" %%d in ('fsutil fsinfo drivetype %%c') do (
if %%d equ Removable (
echo Drive %%c is Removable (USB^)
call "F:\scripts\backups\Backup.bat" %%c
set isUSBfound=true
)
)
)
)
if not %isUSBfound%==true (
echo USB drive not found. Enter USB drive and press enter to try again.
pause
goto tryAgain
)
date /t
time /t
pause
You can perform a wmi call that will give you that information:
$UsbDrives = Get-WmiObject -Class Win32_DiskDrive -Filter 'InterfaceType = "USB"'
If ($UsbDrives)
{
ForEach ($Drive in $UsbDrives)
{
Write-Output "Drive '$($Drive.Caption)' is removable"
}
}
Else
{
Write-Output 'USB drive not found. Enter a USB and try again.'
}
Bit of a pain due to how far you have to walk from a disk drive where the interface type is to a logical disk where the drive letter is, but the newer CIM cmdlets are still much easier to use than doing everything with Get-WMIObject:
Get-CimInstance -Class Win32_DiskDrive -Filter 'InterfaceType = "USB"' |
Get-CimAssociatedInstance -ResultClassName Win32_DiskPartition |
Get-CimAssociatedInstance -ResultClassName Win32_LogicalDisk |
Format-List *
Or:
Get-CimInstance -Class Win32_DiskDrive -Filter 'InterfaceType = "USB"' |
Get-CimAssociatedInstance -Association Win32_DiskDriveToDiskPartition |
Get-CimAssociatedInstance -Association Win32_LogicalDiskToPartition |
Format-List *
The commands are equivalent.
If you're on PowerShell v2.0, you won't have access to the Get-Cim* cmdlets. Try this instead:
Get-WmiObject -Class Win32_DiskDrive -Filter 'InterfaceType = "USB"' |
ForEach-Object {
Get-WmiObject -Query "ASSOCIATORS OF {Win32_DiskDrive.DeviceID=""$($_.DeviceID.Replace('\','\\'))""} WHERE AssocClass = Win32_DiskDriveToDiskPartition"
} | ForEach-Object {
Get-WmiObject -Query "ASSOCIATORS OF {Win32_DiskPartition.DeviceID=""$($_.DeviceID.Replace('\','\\'))""} WHERE AssocClass = Win32_LogicalDiskToPartition"
} |
Format-List *
You may also want some information that is present within Win32_Volume, but there is no way to map the above three classes (Win32_DiskDrive, Win32_DiskPartition, and Win32_LogicalPartition) directly to a Win32_Volume. This is because a Win32_Volume represents a volume mount point, which isn't a concept in the other three classes. The first three classes use the WinCIM32 provider, while the latter uses the storage volume provider. Be careful that you understand the type of system you're looking at before you start matching the two up because they don't necessarily refer to the same types of things. The storage volume provider was introduced in Windows 7 and Server 2008 R2, so the Win32_Volume class won't be available prior to that.

PowerShell Script Not Working as Expected (foreach loop)

I'm using below PowerShell script to set server power plan to High Performance mode. The issue is, it's making changes only to the server where the I'm executing the script even after passing server names through a text file (Servers.txt). I've used foreach loop to iterate through the server list, but still no luck. Not sure where I'm missing the logic, can someone help with this. Thanks in advance.
$file = get-content J:\PowerShell\PowerPlan\Servers.txt
foreach ( $args in $file)
{
write-host "`r`n`r`n`r`nSERVER: " $args
Try
{
gwmi -NS root\cimv2\power -Class win32_PowerPlan -CN $args | select ElementName, IsActive | ft -a
#Set power plan to High Performance
write-host "`r`n<<<<<Changin the power plan to High Performance mode>>>>>"
$HighPerf = powercfg -l | %{if($_.contains("High performance")) {$_.split()[3]}}
$CurrPlan = $(powercfg -getactivescheme).split()[3]
if ($CurrPlan -ne $HighPerf) {powercfg -setactive $HighPerf}
#Validate the change
gwmi -NS root\cimv2\power -Class win32_PowerPlan -CN $args | select ElementName, IsActive | ft -a
}
Catch
{
Write-Warning -Message "Can't set power plan to high performance, have a look!!"
}
}
The problem is that although a foreach loop is used to iterate all the servers, the names are never used for actual power configuration. That is,
$HighPerf = powercfg -l | %{if($_.contains("High performance")) {$_.split()[3]}}
will always be executed on the local system. Thus, no power plan is changed on remote server.
As a work-around, maybe psexec or Powershell remoting would do, as powercfg doesn't seem to support remote system management.
The MS Scripting Guys have a WMI based solution too, as usual.
From the Gist of your Question,I think you may wanna try running the complete Set of commands in Invoke-Command Invoke-Command Documentation and pass the system name in -ComputerName
$file = get-content J:\PowerShell\PowerPlan\Servers.txt
foreach ( $args in $file)
{
invoke-command -computername $args -ScriptBlock {
write-host "`r`n`r`n`r`nSERVER: " $args
Try
{
gwmi -NS root\cimv2\power -Class win32_PowerPlan -CN $args | select ElementName, IsActive | ft -a
#Set power plan to High Performance
write-host "`r`n<<<<<Changin the power plan to High Performance mode>>>>>"
$HighPerf = powercfg -l | %{if($_.contains("High performance")) {$_.split()[3]}}
$CurrPlan = $(powercfg -getactivescheme).split()[3]
if ($CurrPlan -ne $HighPerf) {powercfg -setactive $HighPerf}
#Validate the change
gwmi -NS root\cimv2\power -Class win32_PowerPlan -CN $args | select ElementName, IsActive | ft -a
}
Catch
{
Write-Warning -Message "Can't set power plan to high performance, have a look!!"
}
}
}

How to verify whether a windows server has mountpoint or not using WMI

I am generating a report where I need to find which servers has mountpoints configured on it..
can you help how to get that infor using WMI or powershell.
I mean I need to identify the servers, if mountpoints exists in it.. and also their names....
Get a list of all servers from textfile, AD, etc. and run a foreach loop with something like this:
Get-Wmiobject -query “select name,driveletter,freespace from win32_volume where drivetype=3 AND driveletter=NULL” -computer servername
A quick google search for "windows mount point wmi" would return THIS (source).
Then export the results to CSV, HTML or whatever you need. Your question is lacking a lot of details and any sign of effort from your part, so I can't/won't go any further.
UPDATE: Does this help? It lists mount points(folder paths, not driveletters).
$servers = #("server1","server2","server3","server4","server5")
$servers | % {
$mountpoints = #(Get-WmiObject Win32_MountPoint -ComputerName $_ | Select-Object -ExpandProperty Directory | ? { $_ -match 'Win32_Directory.Name="(\w:\\\\.+)"' }) | % { [regex]::Match($_,'Win32_Directory.Name="(\w:\\\\.+)"').Groups[1].Value -replace '\\\\', '\' }
if($mountpoints.Count -gt 0) {
New-Object psobject -Property #{
Server = $_
MountPoints = $mountpoints
}
}
}
Server MountPoints
------ -----------
{server1} {D:\SSD, C:\Test}

How to list all virtual directories for a IIS6 web site using WMI with powershell?

I've looked at this question Getting all virtual directories for a IIS6 web site using WMI but it doesn't answer my question.
I can get a list of the web sites but not the applications or virtual directories in them. I've tried the following.
Get-WmiObject -class "IIsWebServerSetting" -namespace "root\microsoftiisv2" | select-object __SERVER, ServerComment, Name
Get-WmiObject -class "IIsWebVirtualDir" -namespace "root\microsoftiisv2" | select-object __SERVER, ServerComment, Name, Path, DefaultDoc
Get-WmiObject -class "IIsWebVirtualDirSetting" -namespace "root\microsoftiisv2" | select-object __SERVER, ServerComment, Name, Path, DefaultDoc
None of these retrieve a list of virtual directories.
I can see the virtual directories in the metabase.xml file
<IIsWebVirtualDir Location ="/LM/W3SVC/1653786949/root/PBSNET2005/GUI"
AccessFlags="AccessExecute | AccessRead | AccessScript"
AppFriendlyName="ClientServicesGUI"
The reason why i requires this is because i want to use a green/blue deployment process. To determine which version to update i need to find out what the current version is. I will use the physical path of the virtual directory to do this.
Does anyone have an alternative method of obtain the physical path of a virtual directory? Has anyone ever queried or updated the metabase.xml file directly?
Try this:
gwmi -Namespace "root/MicrosoftIISv2" -Query "SELECT * FROM IIsWebVirtualDirSetting" | select name,path,AppFriendlyName
You need to specify the path to the virtual directory. Virtual directories further down the folder tree are not returned by WMI. Here is the powershell function if anyone requires it.
function Get-VirtualDirectoryPhysicalPathUsingWMI ([string]$server,[string]$siteName,[string]$vDirName,[string]$pathToVDir)
{
Invoke-Command $server -Script { param($siteName,$vDirName,$pathToVDir)
$iisWmiObj = Get-WmiObject -Namespace 'root\MicrosoftIISv2' -Class IISWebServerSetting -Filter "ServerComment = '${siteName}'"
$objIIS = new-object System.DirectoryServices.DirectoryEntry("IIS://localhost/" + $iisWmiObj.Name + $pathToVDir )
$directories = $objIIS.psbase.children
$vDir = $directories.find($vDirName, "IIsWebVirtualDir")
return $vDir.path
} -Args $siteName,$vDirName,$pathToVDir
#Get-VirtualDirectoryPhysicalPathUsingWMI "pbsdevmaintws02" "Default Web Site" "GUI" "/Root/PBSNET2005"
}