I have Powershell code like this:
$disks = Get-WmiObject -Class Win32_MappedLogicalDisk -Filter "DeviceID='Z:'"
foreach($disk in $disks)
{
[Console]::WriteLine("Object: " + $disk.Name + " is " + $disk.ProviderName );
}
But it selects objects outside of the current session, like other users on the terminal session. How can I limit this to objects only under the current session?
You can use this:
gwmi Win32_LogicalDisk -Filter "DeviceID='Z:' " | ? { $_.drivetype -eq 4 }
the where condition it's only to be sure is a network drive and not other kind of unit.
You can read here other drivetype code
Related
Ive a script that emails information of login to us.
I am calling username like this :
$username = Get-WmiObject Win32_Process -Filter "Name='explorer.exe'" | ForEach-Object { $_.GetOwner() } | Select-Object -Unique -Expand User
The reason i am doing this as someone helped me to avoid the username from task manager and call the real users that are logged in instead of the account the task is running under.
The issue I am having is as there are multiple users logged in I am getting System.Object[] returned to me instead of the actually results.
Here is an example of my code :
$IP = Get-NetTCPConnection -state ESTABLISHED -Localport 3389 | Select -ExpandProperty RemoteAddress
$username = Get-WmiObject Win32_Process -Filter "Name='explorer.exe'" | ForEach-Object { $_.GetOwner() } | Select-Object -Unique -Expand User
Then I just call these in my body as so :
$message = "`nUsername :",$username ,....etc
$body = $message
Would anyone know why this would be returning System.Object[]?
Thank you.
The powershell syntax "abc","def" is the same as #("abc","def") both of which returns a string array.
You could use one of these syntaxes instead:
$message = "`nUsername : $username"
$message = "`nUsername : " + $username
In case you get several user names (maybe "$usernames" would be more suitable), just use something like
$message = "`nUsernames : " + $usernames -join ", "
In case you don't know if you get 1 or more usernames, you might want to use this instead:
$username = #(Get-WmiObject [...] -Expand User)
Hi All,
I was hoping if someone has done this scenario before. I'm looking for a PowerShell script to gather PC Hardware details in the local network. it's Windows 7,10 and not in DC.
Details I would like to get from each PC is
RAM (name and size)
CPU (name and size)
HDD (name and size)
Local User profiles
Is it something possible (logically I can't see how it's possible) as PC's are not in a domain.
Any suggestions would helpful
Love & Peace
My fellow humans
This should do the trick:
Add-Type -AssemblyName System.Collections
[System.Collections.Generic.List[string]]$hdd = #()
$system = Get-CimInstance CIM_ComputerSystem
$cpu = Get-CimInstance CIM_Processor
$users = Get-WmiObject -ComputerName "localhost" -Class Win32_UserAccount -Filter "LocalAccount='True'" |Select PSComputername, Name, Status, Disabled, AccountType, Lockout, PasswordRequired, PasswordChangeable, SID
$driveLetter = 'C'
$currentHdd = Get-CimInstance Win32_LogicalDisk -Filter "DeviceID = '$($driveletter):'"
while( $currentHdd.DeviceID ) {
switch( $currentHdd.DriveType ) {
3 {
$driveType = "HDD"
break;
}
5 {
$driveType = "Optical"
break;
}
default {
$driveType = "Other"
}
}
$drive = $driveletter + ': ' + $driveType + (" {0:N2}" -f ($currentHdd.Size/1GB) + " GB ") + ("{0:N2}" -f ($currentHdd.FreeSpace/1GB) + " GB ")
$hdd.Add( $drive )
$driveLetter = ([char](++([byte]([char]$driveLetter)))).ToString()
$currentHdd = Get-CimInstance Win32_LogicalDisk -Filter "DeviceID = '$($driveletter):'"
}
$ram = "{0:N2}" -f ($system.TotalPhysicalMemory/1GB) + " GB"
$cpuName = $cpu.Name
"CPU: $cpuName"
"RAM: $ram"
"Disks:"
$hdd
"Users:"
$users
This will do the trick for machines NOT on domain.
You will need:
IP Address(s)
Admin login credentials for the remote machine
Below syntax will query Windows7-Windows10 machines for RAM, CPU, HDD and User profiles:
wmic /NODE:"127.0.0.1" memorychip get capacity & wmic /NODE:"127.0.0.1" cpu list brief & wmic /NODE:"127.0.0.1" diskdrive get Name, Manufacturer, Model & wmic /NODE:"127.0.0.1" useraccount get name
For the example above, I'm simply using loopback IP (queries the local PC you are on), but you can substitute any IP address.
You can also specify your credentials to the wmic tool if needed. Learn more about wmic here:
https://learn.microsoft.com/en-us/windows/win32/wmisdk/wmic
i have to identify all the laptops in our organization.
single OU named "computers". all the computers are named by the name of the user using it. no information about the computer type.
in order to deploy a soft on laptops only, i have to "isolate" them.
i ran the following script.
$ErrorActionPreference = "silentlyContinue"
$coms=Get-ADComputer -Filter * -SearchBase "CN=Computers,DC=domain,DC=com" |select -exp name
Foreach($com in $coms)
{
Get-WmiObject win32_computersystem -comp $com | Select-Object PCSystemType,Name,Manufacturer,Model | format-table
}
it works pretty good. but not so easy to sort.
i wanted to make it better, and ran the following:
$ErrorActionPreference = "silentlyContinue"
$coms=Get-ADComputer -Filter * -SearchBase "CN=Computers,DC=domain,DC=com" |select -exp name
Foreach($com in $coms)
{
Get-WmiObject win32_computersystem -comp $com| Select-Object PCSystemType,Name,Manufacturer,Model | format-table
if ($com.PCSystemType -eq '2'){Write-host "$com is a laptop"}
else {Write-host "$com is a desktop"}
}
i now have this result:
COMP1 is a desktop
COMP2 is a desktop
COMP3 is a desktop
COMP4 is a desktop
LAPTOP1 is a desktop
LAPTOP2 is a desktop
LAPTOP3 is a desktop
Both laptops and desktops are desktops according my script.
what i did wrong?
any tip would help! thanks
The purpose of the Format-* cmdlets is to create pretty output to the console; to be human-readable. It does this by creating different objects from what you pass in to accomplish an ends. As a result, you have unusable objects and are essentially accessing $null.
Removing | Format-Table will fix your problem.
You need to store the value of your WMI query in a variable before evaluating it in your if loop.
Slightly modified version:
$coms = #("localhost")
Foreach($com in $coms) {
$wmi = Get-WmiObject win32_computersystem -comp $com
switch ($wmi.PCSystemType) {
'0' { "$com is a Unspecified " }
'1' { "$com is a Desktop " }
'2' { "$com is a Mobile " }
'3' { "$com is a Workstation " }
'4' { "$com is a Enterprise Server" }
'5' { "$com is a SOHO Server" }
'6' { "$com is a Appliance PC" }
'7' { "$com is a Performance Server" }
'8' { "$com is a Maximum" }
Default { "Unable to get correct value for $com" }
}
}
I have the following script to find the process "dotnet.exe". In my system, I have many dotnet.exe processes running. But I want to kill the "dotnet.exe" which has command line argument "MyService\Web\argument". I'm trying to do it by the following script. But it doesn't find anything, although I see the process in the Task Manager.
$process = Get-WmiObject Win32_Process | select name, commandline
foreach ($p in $process)
{
if ($p.name -contains "dotnet.exe" -and $p.commandline -contains "web")
{
$kp = Get-Process $p;
$kp.CloseMainWindow();
if (!$kp.HasExited)
{
$kp | Stop-Process -Force
}
}
else
{
Write-Host name: $p.name and param: $p.commandline;
}
}
All you need to do is filter the process list directly via Get-WmiObject and then terminate the matching process(es):
$fltr = "name like '%dotnet.exe%' and commandline like '%web%'"
Get-WmiObject Win32_Process -Filter $fltr | ForEach-Object {
$_.Terminate()
}
You could also call Terminate() directly on the output of Get-WmiObject like this:
(Get-WmiObject Win32_Process -Filter $fltr).Terminate()
However, there are situations where this could fail, e.g. if Get-WmiObject doesn't return any results, or if you're using PowerShell v2 or earlier and Get-WmiObject returns more than one result (passing a method call to the members of an array requires member enumeration, which was introduced with PowerShell v3). Using a ForEach-Object loop is both more robust and backwards-compatible.
The Get-WmiObject cmdlet returns quite useful objects, but you have stripped off everything by selecting only the Name and CommandLine parameters:
$process = Get-WmiObject Win32_Process | select name, commandline
If you remove the | select name, commandline part, you can still loop through each process but also make use of methods like Terminate() that will still be available.
You could do it in one shot, as per #ansgar-wiechers comment, or still make use of the loop and add in more logging, etc. if you wanted:
$process = Get-WmiObject Win32_Process
foreach($p in $process){
if($p.Name -eq "*dotnet.exe" -and $p.CommandLine -like "*web*"){
$p.Terminate()
# and so on...
}
}
Note also the comment from #TheIncorrigible1 about the use of comparison operators. I have used -eq for the process name and -like for the command line.
I have many servers I need to remove Symantec Endpoint Protection from. I contacted Symantec and received the code below:
(Get-WmiObject -Class Win32_Product -Filter "Name='Symantec Endpoint Protection'" -ComputerName xxxxxx).Uninstall()
I have used it and it worked on 10 servers no problem at all. I tried it again today and am getting the error:
You cannot call a method on a null-valued expression.
At line:1 char:1
+ (Get-WmiObject -Class Win32_Product -Filter "Name='Symantec Endpoint Protection' ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Nothing has changed from when I started and am trying to figure out what the above error means. Also if I can get this to work does anyone see a way to add many servers to a foreach command or something.
Two things from my side:
1) you should not use win32_product cause it is broken to a certain level.
It is very slow alsso because it scans the entire thing.
2) In your case, "Name='Symantec Endpoint Protection'" reports Null for you which means that the value is not there. Please check the proper name.
For better performance and as part of enhancement , you should use the registry to fetch the details.
Function Get-RemoteSoftware{
<#
.SYNOPSIS
Displays all software listed in the registry on a given computer.
.DESCRIPTION
Uses the SOFTWARE registry keys (both 32 and 64bit) to list the name, version, vendor, and uninstall string for each software entry on a given computer.
.EXAMPLE
C:\PS> Get-RemoteSoftware -ComputerName SERVER1
This shows the software installed on SERVER1.
#>
param (
[Parameter(mandatory=$true,ValueFromPipelineByPropertyName=$true)][string[]]
# Specifies the computer name to connect to
$ComputerName
)
Process {
foreach ($Computer in $ComputerName)
{
#Open Remote Base
$reg=[microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine',$Computer)
#Check if it's got 64bit regkeys
$keyRootSoftware = $reg.OpenSubKey("SOFTWARE")
[bool]$is64 = ($keyRootSoftware.GetSubKeyNames() | ? {$_ -eq 'WOW6432Node'} | Measure-Object).Count
$keyRootSoftware.Close()
#Get all of they keys into a list
$softwareKeys = #()
if ($is64){
$pathUninstall64 = "SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
$keyUninstall64 = $reg.OpenSubKey($pathUninstall64)
$keyUninstall64.GetSubKeyNames() | % {
$softwareKeys += $pathUninstall64 + "\\" + $_
}
$keyUninstall64.Close()
}
$pathUninstall32 = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
$keyUninstall32 = $reg.OpenSubKey($pathUninstall32)
$keyUninstall32.GetSubKeyNames() | % {
$softwareKeys += $pathUninstall32 + "\\" + $_
}
$keyUninstall32.Close()
#Get information from all the keys
$softwareKeys | % {
$subkey=$reg.OpenSubKey($_)
if ($subkey.GetValue("DisplayName")){
$installDate = $null
if ($subkey.GetValue("InstallDate") -match "/"){
$installDate = Get-Date $subkey.GetValue("InstallDate")
}
elseif ($subkey.GetValue("InstallDate").length -eq 8){
$installDate = Get-Date $subkey.GetValue("InstallDate").Insert(6,".").Insert(4,".")
}
New-Object PSObject -Property #{
ComputerName = $Computer
Name = $subkey.GetValue("DisplayName")
Version = $subKey.GetValue("DisplayVersion")
Vendor = $subkey.GetValue("Publisher")
UninstallString = $subkey.GetValue("UninstallString")
InstallDate = $installDate
}
}
$subkey.Close()
}
$reg.Close()
}
}
}
Note: Use the function or the query inside the function to get the result.
Hope it helps.