I have some requirement where I have to find out the current version and update details of an installed application (highlighted):
And I have this PowerShell snippet for modification:
$server="XXXXXXXXXX"
$ServiceInfo = Get-WmiObject win32_service -ComputerName $server -ExpandProperty Version | Where-Object {$_.Name -eq "VSTTAgent"}
if($ServiceInfo.State -eq "Running")
{
$userAccount = $ServiceInfo.DisplayName.ToString()
Write-Host ("VSTTAgent service is Running on $server and $userAccount ")
}
To get the product version, you can use the Get-Item cmdlet using the PathName property of your $ServiceInfo object:
$ServiceInfo.PathName.Trim('"') | Get-Item | select -expand VersionInfo | select ProductVersion
Essentially the same as #MartinBrandl, but the WMI-only version.
Get-WmiObject win32_service -Filter 'Name="VSTTAgent"' -ComputerName $server | ForEach-Object {
$filter = 'Name="{0}"' -f $_.PathName -replace '\\', '\\'
$version = (Get-WmiObject CIM_DataFile -Filter $filter -ComputerName $server).Version
if ($_.State -eq 'Running') {
$userAccount = $ServiceInfo.DisplayName.ToString()
Write-Host ("VSTTAgent ($version) service is Running on $server and $userAccount")
}
}
Related
Below Function is not running the lines "If ($script:AADServersTable)" down... I have put a write-host and that is working, however the variables are not working below that
Function get-AADVariables
{
$script:AADServersTable = New-Object 'System.Collections.Generic.List[System.Object]'
$scriptBlockaadinstalled = {
Get-WmiObject -Class Win32_Product |
where name -eq "Microsoft Azure AD Connect synchronization services" | select Name, Version}
##$scriptBlockaadinstalled = {hostname}
Import-Module ActiveDirectory
$servers = Get-ADComputer -Filter 'operatingsystem -like "*server*" -and enabled -eq "true"' | Select-Object -Property Name -ExcludeProperty Release
## just a single invoke-command
foreach ($server in $servers) {
$aadinstalledresults = Invoke-Command -ComputerName $server.name -ScriptBlock $scriptBlockaadinstalled ##-HideComputerName
$aadinstalledresults = $aadinstalledresults.PSComputerName
$script:AADServersTable.Add($aadinstalledresults)
}
If ($script:AADServersTable) {
Write-Host 'working'
$AADServers = ($script:AADServersTable | Group-Object -NoElement).Name | Get-Unique
$AADServers = $AADServers -split "`n"
$AADServer = $AADServers[0]
$StandByAADServer = $AADServers[1]
$SecondStandByAADServer = $AADServers[2]
}
}
I wrote this small script and when I test Write-Host $serial it appears fine, but when it is running in the background $serial seems to contain an array.
It tries to rename computer to C000#{SerialNumber=F7ZL3F2} instead of just C000F7ZL3F2.
What should I do to just get string not this array?
Import-Module ActiveDirectory
Get-ADComputer -Filter {Name -like 'DESKTOP-*'} -Properties * | Select Name, DNSHostName | ForEach-Object {
$rtn = Test-Connection -CN $_.dnshostname -Count 1 -BufferSize 16 -Quiet
if ($rtn -match 'True') {
$serial = Get-WMIObject Win32_Bios -ComputerName $_.name | Select-String SerialNumber
$serial = "C000$serial"
// Write-Host $serial
Rename-Computer -ComputerName $_.name -NewName $serial -DomainCredential $mycreds -Force -Restart
}
}
There are two mistakes to be pointed out in your code -
$serial = Get-WMIObject Win32_Bios -ComputerName $_.name | Select-String SerialNumber
The Select-String cmdlet searches for text and text patterns in input strings and files. Where as the basetype output of Get-WMIObject Win32_Bios is System.Management.ManagementBaseObject
(Get-WMIObject Win32_Bios).Gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True ManagementObject System.Management.ManagementBaseObject
In such cases, instead of Select-String, you can use Select-Object to choose amongst the properties. Since, Serial Number is one of the properties returned by your input command.
$serial = "C000$serial"
The output of $serial will be something like this:
SerialNumber
5CXXXXYYYXZZZ
Again, you can call it directly by $serial.SerialNumber. So your overall code will be
Import-Module ActiveDirectory
Get-ADComputer -Filter {Name -like 'DESKTOP-*'} -Properties * | Select Name, DNSHostName | ForEach-Object {
$rtn = Test-Connection -CN $_.dnshostname -Count 1 -BufferSize 16 -Quiet
if ($rtn -match 'True') {
$serial = Get-WMIObject Win32_Bios -ComputerName $_.name |
Select-Object SerialNumber
$serial = "C000$($serial.SerialNumber)"
Rename-Computer -ComputerName $_.name -NewName $serial -DomainCredential $mycreds -Force -Restart
}
}
Or you can use -ExpandProperty parameter of the Select-Object cmdlet like
$serial = Get-WMIObject Win32_Bios -ComputerName $_.name |
Select-Object -ExpandProperty SerialNumber
$serial = "C000$serial"
Try changing this line:
$serial = Get-WMIObject Win32_Bios -ComputerName $_.name |
Select-String SerialNumber
to this:
$serial = (Get-WMIObject Win32_Bios -ComputerName $_.name).SerialNumber
or this:
$serial = Get-WMIObject Win32_Bios -ComputerName $_.name |
Select-Object -ExpandProperty SerialNumber
Why are you using Select-String? I would use Select-Object and then -ExpandProperty
Import-Module ActiveDirectory
Get-ADComputer -Filter {Name -like 'DESKTOP-*'} -Properties * | Select Name, DNSHostName | ForEach-Object {
$rtn = Test-Connection -CN $_.dnshostname -Count 1 -BufferSize 16 -Quiet
if ($rtn -match 'True') {
$serial = Get-WMIObject Win32_Bios -ComputerName $_.name | Select-Object -ExpandProperty SerialNumber
$serial = "C000$serial"
// Write-Host $serial
Rename-Computer -ComputerName $_.name -NewName $serial -DomainCredential $mycreds -Force -Restart
}
}
I have the following short script to grab serial numbers of computers and monitors in an OU, which works fine:
Import-Module ActiveDirectory
$searchbase = "OU=some,OU=organisational,OU=units,DC=somedomain,DC=local"
Write-Host ""
Write-Host "Serial Numbers for Computers and Monitors in" $searchbase
Write-Host "--"
Get-ADComputer -SearchBase $searchbase -Filter '*' | `
Select-Object -Expand Name | %{Write-Host ""; echo $_ ; Get-WMIObject -Class Win32_BIOS -ComputerName $_ | Select-Object -Expand SerialNumber; `
$monitor = gwmi WmiMonitorID -Namespace root\wmi -computername $_; ($monitor.SerialNumberID | foreach {[char]$_}) -join ""};
This script doesn't check to see if the computer is online before attempting to fetch the WMIObject, so if a computer is offline it takes ages before the RPC call times out.
I tried to modify the script to use the Test-Connection cmdlet before trying to get the WMIObject:
Import-Module ActiveDirectory
$searchbase = "OU=some,OU=organisational,OU=units,DC=somedomain,DC=local"
Write-Host ""
Write-Host "Serial Numbers for Computers and Monitors in" $searchbase
Write-Host "--"
Get-ADComputer -SearchBase $searchbase -Filter '*' | `
Select-Object -Expand Name | `
if (Test-Connection -ComputerName $_ -Quiet) {
%{Write-Host ""; echo $_ ; Get-WMIObject -Class Win32_BIOS -ComputerName $_ | Select-Object -Expand SerialNumber; `
$monitor = gwmi WmiMonitorID -Namespace root\wmi -computername $_; ($monitor.SerialNumberID | foreach {[char]$_}) -join ""};}
}
else {
Write-Host ""; Write-Host $_ "is offline";
}
I'm sure I'm doing something syntactically stupid. Can someone point me in the right direction?
You can't pipe directly to an if statement, only to cmdlets.
Put the if statement inside the ForEach-Object block (% is an alias for ForEach-Object):
... | Select-Object -Expand Name | `
%{
if (Test-Connection -ComputerName $_ -Quiet) {
# Get-WmiObject in here
}
else {
Write-Host ""; Write-Host $_ "is offline";
}
}
If you don't care about writing each machine's status to the host, you could also filter out offline computers with Where-Object(alias ?):
... | Select-Object -Expand Name | ?{
Test-Connection $_ -Quiet
} | % {
Get-WmiObject -ComputerName $_
}
In addition to the answer from #Mathias R. Jessen, you can get rid of the backticks for line continuation.
They are not needed if the end of the line infers there is another block of code required for the statement. Like | or { or (.
"foo", "bar" |
% {$_}
works just fine...
I'm trying to return tables with message queues from three different environments. I could copy and paste the existing code for all three, but I want to make it cleaner and more reusable.
Is there a way to loop through each message queue and return them in separate tables (i.e.: Dev, Dev2, Dev3 queues)?
[object]$dev3Queues = gwmi -class Win32_PerfFormattedData_msmq_MSMQQueue -computerName myServer | Where{$_.Name -like "*dev3*" } | select Name,MessagesInQueue #| Out-File "C:\test.txt"
[object]$dev2Queues = gwmi -class Win32_PerfFormattedData_msmq_MSMQQueue -computerName myServer | Where{$_.Name -like "*dev2*" } | select Name,MessagesInQueue #| Out-File "C:\test2.txt"
[object]$devQueues = gwmi -class Win32_PerfFormattedData_msmq_MSMQQueue -computerName myServer |
Where{$_.Name -notlike "*dev2*" -AND $_.Name -notlike "*dev3*" -AND $_.Name -notlike "*private*" -AND $_.Name -notlike "*Computer Queues*" -AND $_.Name -notlike "*uat*"} | select Name,MessagesInQueue #| Out-File "C:\test3.txt"
$Html = "<html><head>Whoo Queues</head><body><table border=1>"
foreach($element in $devQueues)
{
$Html += "<tr><td>" + $element.Name + "</td><td>"+ $element.MessagesInQueue + "</td> </tr>"
}
$Html += "</table></body></html>"
$Html | out-file C:\temp\DEVQueues.html
#environmentloop - dev,dev2,dev3
#{
#queue loop + html
#}
You can use the ConvertTo-Html cmdlet with the option -Fragment to convert a list of objects to an HTML table of the object properties.
Get-WmiObject -Class Win32_PerfFormattedData_msmq_MSMQQueue |
select Name, MessagesInQueue |
ConvertTo-Html -Fragment
Also, when running Get-WmiObject against a remote server using a WMI filter provides better performance than retrieving all results and filtering them on the local host with Where-Object.
$computer = 'myServer'
$filter = 'Name LIKE "%dev3%"'
Get-WmiObject -Class Win32_PerfFormattedData_msmq_MSMQQueue -Computer $computer `
-Filter $filter
However, since you want to filter the same dataset for various criteria, in your case the best approach might be to first fetch all relevant data from the remote host with a more general WMI filter (to avoid multiple remote connections), and then process them locally with several Where-Object filters:
$server = 'myServer'
$wmiFilter = 'NOT (Name LIKE "%private%" OR Name LIKE "%Computer Queues%" ' +
'OR Name LIKE "%uat%")'
$psFilters = { $_.Name -like "*dev3*" },
{ $_.Name -like "*dev2*" },
{ $_.Name -notlike "*dev2*" -and $_.Name -notlike "*dev3*" }
$data = Get-WmiObject -Class Win32_PerfFormattedData_msmq_MSMQQueue `
-Computer $server -Filter $wmiFilter
'<html><head>Whoo Queues</head><body>'
foreach ($filter in $psFilters) {
$data | ? $filter | select Name, MessagesInQueue | ConvertTo-Html -Fragment
}
'</body></html>'
I can only get the command to return the services on the first computer in the text file.
Is there a better way than for-each for this task?
Get-Service *vault* -ComputerName (Get-Content c:\users\sean\desktop\js.txt) | select name,status,machinename | sort machinename | format-table -autosize
Try it without the get-content. Try this:
Get-Service *vault* -ComputerName c:\users\sean\desktop\js.txt | select name,status,machinename | sort machinename | format-table -autosize
If that doesn't work, then try:
$Computers = Get-Content c:\users\sean\desktop\js.txt
Get-Service *vault* -computername $Computers | Select name,status,machinename |sort machinename |format-table -autosize
If you are eager for a one-liner then try this:
Get-Content c:\users\sean\desktop\js.txt | Get-Service *vault* | Select name,status,machinename |sort machinename |format-table -autosize
I would try the top one first. I would test, but I don't have access to anything I can do a proper test right now.
$Computers = get-content .\desktop\test.txt
$Service = "Vault"
foreach ($computer in $computers) {
$computer
$Servicestatus = get-service -name $Service -ComputerName $computer
}
$Servicestatus | select-object Name,Status,MachineName | format-table -Autosize
This works for me, it gives me each of the computers in the text file, and it looks for the service.
This is what I use. I get the list of computers from an OU in AD.
Import-Module ActiveDirectory
$ou = "OU=Servers,DC=Domain,DC=com"
$servers = Get-ADComputer -Filter * -SearchBase $ou | select-object -expandproperty name
Foreach ($server in $servers){
$Data = Get-Service -ServiceName *IIS*,*TomCat*,*httpd* -ComputerName $server | select machinename,name | sort machinename | format-table -AutoSize
Write($Data) | Out-File .\WebServices.txt -Append
}
$servers = Get-Content .\servers.txt
Foreach ($server in $servers) {
"$server"
Get-Service -ComputerName $Server -name -like "*vault*"
"-------------------"
}
Following a memory limitation limit with older versions of PowerShell, I was required to refresh my code:
Old code:
gwmi win32_service -computer $allcomputers | Select-Object __SERVER,Name,state,startmode,StartName
New code:
`$servers = Get-Content "computers.txt"
Foreach ($server in $servers) {
Get-WmiObject -Class WIN32_service -ComputerName $server |
Select-Object __SERVER,Name,state,startmode,StartName |
Export-Csv -path "Report.CSV" -NoTypeInformation -Append
}`
This is how you can get list of all services in your AD domain:
Get-ADComputer -Filter {OperatingSystem -Like “Windows 10*”} | ForEach-Object {Get-WmiObject -Class Win32_Service -Computer $_.Name}
More useful examples on this (get list of services for all computer listed in a text file, etc.):
https://www.action1.com/kb/list_of_services_on_remote_computer.html
Get-Service -ComputerName ... has a bug in PowerShell 2.0 that only returns the first computer. This is fixed in newer versions so if you upgrade to PowerShell 3.0 or newer, your original code will work fine.
As a workaround, use a foreach-loop to run Get-Service once for each computer:
Get-Content c:\users\sean\desktop\js.txt |
ForEach-Object { Get-Service -Name *vault* -ComputerName $_ } |
Select-Object -Property Name, Status, MachineName |
Sort-Object -Property MachineName |
Format-Table -AutoSize
Nick's solution totally doesn't work for me. I ended up writing a quick and dirty one that works:
$servers = Get-Content .\servers.txt
Foreach ($server in $servers) {
"$server"
Get-Service *vault*
"-------------------"
}