Powershell variable not being populated - powershell

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

Related

PowerShell interrogate a remote system

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.

Get-WmiObject : Invalid class "SoftwareLicensingProduct"

I'm new to powershell and am trying to write a program that will get the product key of numerous servers.
I am looping through the server names and trying to do the following code but am getting the error in the title
$LicenseInfo = Get-WmiObject -Class SoftwareLicensingProduct -ComputerName $target -Credential $cred | `
Where-Object { $_.PartialProductKey -and $_.ApplicationID -eq "55c92734-d682-4d71-983e-d6ec3f16059f" } | Select-Object PartialProductKey, Description, ProductKeyChannel, #{ N = "LicenseStatus"; E = { $lstat["$($_.LicenseStatus)"] } }
Any help would be appreciated
That error is very specific. Are you targeting machines that do not have this class available? As per learn.microsoft.com for SoftwareLicensingProduct:
Minimum supported client: Windows 7
Minimum supported server: Windows Server 2008 R2

PowerShell WMI query fails to return username in logon script

I'm trying to get the username of domain users in a PowerShell logon script. Any number of different users may log into the computers in question.
A local user account (let's call it 'syscheck') is configured on Win7/Win8 domain clients for the purpose of running a PS script (PS 2.0/3.0); the script resides locally and is launched by Task Scheduler on user logon. The script needs to obtain the username of the domain user that is logging in.
I've attempted to do this with WMI:
Get-WmiObject Win32_ComputerSystem | Select-Object -ExpandProperty UserName
but this does not return anything when the script runs.
If I try this:
$env:USERNAME
The username of the 'syscheck' local account is returned.
Is the domain username not yet available when the script is running on logon?
Perhaps there a way to do this with .NET? Other options?
***** UPDATE August 8 *****
I've tested with the solution provided (thanks Alexander!) but still can NOT retrieve the username of the logged-in user. I believe this is because, as mentioned above, this is a logon script launched by Task Scheduler. The principal for the Task that launches the script is a local account. For some reason, all methods of trying to get the domain username fail.
Here is latest attempt:
First, this is how I call the function:
$indx = 0
do {
$username = GetDomUser
if (($indx -eq 25) -or ($username.Length -ne 0)) {
Write-Output $username
Break
}
else {
Start-Sleep -Seconds 12
}
$indx++
}
while ($indx -lt 25) # 5 minutes is PLENTY of time for boot...
Now, here's the function:
Function GetDomUser {
$compname = $($env:COMPUTERNAME)
$pattern = '"MYDOMAIN",Name='
$antecedent = #(Get-WmiObject -Class Win32_LoggedOnUser -ComputerName $compname |
Where-Object { $_.Antecedent -match $pattern } | Select-Object -ExpandProperty Antecedent)
Return ([regex]::Match([string]$antecedent[0],"$pattern(.*$)").Value).Split('=')[1] -replace '"', ""
}
Of course, this works perfectly from the console once the machine has booted.
Is it possible to refresh whatever store the Win32_LoggedOnUser Class gets its data from?
Other options?
Here are previous methods I've tried - all return the username of the principal of the Task that launches the script (or an empty string, which is what D returns).
$usernameA = $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)
$usernameB = $(whoami)
$usernameC = $($env:USERNAME)
$usernameD = $(Get-WmiObject Win32_ComputerSystem -ComputerName $compname | Select-Object -ExpandProperty UserName)
$usernameE = $([Environment]::UserName)
Here's what you could do to find out what's going on:
$iLOGON32_LOGON_INTERACTIVE = 2
$cLogonSessions = Get-WmiObject -Class "Win32_LogonSession" `
| Where-Object { $_.LogonType -eq $iLOGON32_LOGON_INTERACTIVE }
if ($cLogonSessions -ne $null) {
$cInteractiveLogons = #()
foreach ($oLogonSession in $cLogonSessions) {
$sWmiQuery = ('ASSOCIATORS OF {{Win32_LogonSession.LogonId="{0}"}} ' `
+ 'WHERE AssocClass=Win32_LoggedOnUser') -f $oLogonSession.LogonId
$cInteractiveLogons += Get-WMIObject -Query $sWmiQuery `
| Select-Object -ExpandProperty "Caption"
}
} else {
$ex = New-Object -TypeName System.NullReferenceException(`
'$cInteractiveLogons is null.')
throw $ex
}
$cInteractiveLogons | Select-Object -Unique
When $cInterativeLogons is null exception is thrown, it means that no-one is logged on interactively (yet) in which case you can wait and re-check later.
Note that this code is not reliable because LOGON32_LOGON_INTERACTIVE wasn't limited to local console logons in XP and earlier versions.
As for actual solution, I'd recommend using some kind of explicit notifications. You could for example make use of events. Subscribe for an event and then emit the event from the user's regular logon script.
The problem was not with the WMI code but rather the state of the machine it was being run on. It turns out that when users are VPNed into their machines (almost always thanks to a VPN client's automated reconnect feature), or have some third-party utility installed (e.g. certain cloud backup services), there are multiple Logons and "the" logged on user is ambiguous.
For now this is working pretty well:
Function GetDomainUser {
$compname = $($env:COMPUTERNAME)
$pattern = '"' + $($env:USERDOMAIN) + '"' + ',Name='
$antecedent = #(Get-WmiObject -Class Win32_LoggedOnUser -ComputerName $compname |
Where-Object { $_.Antecedent -match $pattern } |
Select-Object -ExpandProperty Antecedent | Select-Object -Unique)
Return $(([regex]::Match([string]$antecedent,$($pattern + '(".+")')).Value).Split('=')[1] -replace '"','')
}
But I had to write addition code to work around cases when the LoggedOnUser cannot be discovered (multiple logons exist), or when no one is logged in.

net localgroup administrators equivalent in powershell

I've configured winrm on all my desktops via GPO, so I can now use the invoke-command cmdlet to run commands locally on remote machines. When I run net localgroup administrators on my local machine this works and gives me what I want. The problem is I cannot do anything with this data. I cannot pipe out the results to a variable so I can lets say remove specific accounts.
Is there a built in cmdlet that will let me do the same as net localgroup administrators ?
While it's possible to run net localgroup groupname and parse its output, it isn't a very PoSh way of doing this. I'd recommend using the WinNT provider instead:
$computers = 'HostA', 'HostB', 'HostC', ...
$groupname = 'Administrators'
$computers | % {
$group = [ADSI]("WinNT://$_/$groupname,group")
$group.PSBase.Invoke('Members') | % {
$_.GetType().InvokeMember('Name', 'GetProperty', $null, $_, $null)
}
}
If you want to use Invoke-Command you could do something like this:
$computers = 'HostA', 'HostB', 'HostC', ...
$groupname = 'Administrators'
Invoke-Command -Computer $computers -ScriptBlock {
$group = [ADSI]("WinNT://$env:COMPUTERNAME/$($args[0]),group")
$group.PSBase.Invoke('Members') | % {
$_.GetType().InvokeMember('Name', 'GetProperty', $null, $_, $null)
}
} -ArgumentList $groupname
You can parse the names from the output.
Here's an example using V4:
(net localgroup administrators).where({$_ -match '-{79}'},'skipuntil') -notmatch '-{79}|The command completed'
Using any version of PowerShell you can simply do the following for whichever machine you want to check:
get-wmiobject -class Win32_Group -computer <computername>(, <computer2> ...)
That will give you the local user accounts. This also gives you ManagementObjects you can use to delete groups if you want, or using PSv3 and newer additional cmdlets are installed on Windows Server (run get-module -list) you can use that may be easier (but still use WMI over WinRM).
I want to build on #Ansgar Wiechers's answer. For my purposes, getting the name of each user was not enough; I had to get the user's domain so that I could see whether the user account was a local account or a domain account.
Instead of calling PSBase.Invoke('Members'), I simply called Members(). To get the path of each user, I casted the object using [ADSI] and then got the Path property. This was the code that I ended up using to get the members of the local Administrators group on the local machine:
([ADSI]"WinNT://localhost/Administrators,group").Members() | % { ([ADSI]$_).Path.Substring(8) }
For multiple computers, it would look like this:
$computers = 'HostA', 'HostB', 'HostC', ...
$computers | % {
([ADSI]"WinNT://$_/Administrators,group").Members() | % {
([ADSI]$_).Path.Substring(8)
}
}
In the end, I extended my script to query all of the computers in my domain, list the local administrators on each computer, and export all of the results to an XML file:
Import-Module ActiveDirectory
Get-ADComputer -Filter { enabled -eq $true } | % {
$result = New-Object PSObject
Add-Member -InputObject $result -MemberType NoteProperty -Name "Name" -Value $_.Name
$local_administrators = ([ADSI]"WinNT://$($_.Name)/Administrators,group").Members() | % { ([ADSI]$_).Path.Substring(8) }
Add-Member -InputObject $result -MemberType NoteProperty -Name "Local Administrators" -Value $local_administrators
$result
} | Export-Clixml "Local Administrators on Machines in the Domain.xml"
You have to install the Remote Server Administration Tools in order to do Import-Module ActiveDirectory. For Windows 7 SP1, you can go to https://www.microsoft.com/en-us/download/details.aspx?id=7887 to download and install the tools and then go to Add or Remove Windows Features to enable them.

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"
}