Get-Service in a Powershell Script - powershell

A basic question - but why in a Powershell Script does Get-Service not print the list to the output?
Write-Host "Enumerating installed Services..." -ForegroundColor Green
Get-Service | Sort-Object status,displayname
Now in the script it gives no output at all.
But if I opened a powershell prompt and typed it manually it works fine.
Full Script:
param([string] $server)
$serverSystem = Get-WmiObject -computername $env:computername Win32_ComputerSystem
$serverCPUDetail = Get-WmiObject -ComputerName $env:computername Win32_Processor
switch ($ComputerSystem.DomainRole){
0 {$ComputerRole = "Standalone Workstation"}
1 {$ComputerRole = "Member Workstation"}
2 {$ComputerRole = "Standalone Server"}
3 {$ComputerRole = "Member Server"}
4 {$ComputerRole = "Domain Controller"}
5 {$ComputerRole = "Domain Controller"}
default {$ComputerRole = "No role available" }
}
$serverOS = Get-WmiObject -class Win32_OperatingSystem -ComputerName $env:computername
Write-Host "Enumerating System information..." -ForegroundColor Green
" "
Start-Sleep -s 1
Write-Host "Hostname:" ($env:computername)
Write-Host "Domain:" ($serverSystem.Domain)
Write-Host "Role:" ($ComputerRole)
Write-Host "Operating System:" ($serverOS.Caption)
Write-Host "Service Pack:" ($serverOS.CSDVersion)
$lastBootTime = $serverOS.ConvertToDateTime($serverOS.Lastbootuptime)
Write-Host "Last Boot Time:" $lastBootTime
" "
Write-Host "Enumerating Hardware information..." -ForegroundColor Green
" "
Start-Sleep -s 1
Write-Host "Model:" ($serverSystem.Model)
Write-Host "Manufacturer:" ($serverSystem.Manufacturer)
Write-Host "CPU - No. of Processors:" ($serverSystem.NumberOfProcessors)
Write-Host "CPU - No. of Cores:" ($serverCPUDetail.NumberofCores)
Write-Host "CPU - No. of Processors, Logical:" ($serverCPUDetail.NumberOfLogicalProcessors)
Write-Host "Memory in GB:" ([math]::round($serverSystem.TotalPhysicalMemory/1024/1024/1024,0))
" "
Write-Host "Enumerating Disk Information..." -ForegroundColor Green
Start-Sleep -s 1
Foreach ($s in $env:computername) {
Get-WmiObject -Class win32_volume -cn $s |
Select-Object #{LABEL='Comptuer';EXPRESSION={$s}},DriveLetter, Label,#{LABEL='Free Space (GB)';EXPRESSION={"{0:N2}" -f ($_.freespace/1GB)}}
}
" "
Write-Host "Enumerating Network Information..." -ForegroundColor Green
" "
Start-Sleep -s 1
ForEach($NIC in $env:computername) {
$intIndex = 1
$NICInfo = Get-WmiObject -ComputerName $env:computername Win32_NetworkAdapterConfiguration | Where-Object {$_.IPAddress -ne $null}
$caption = $NICInfo.Description
$ipAddress = $NICInfo.IPAddress
$ipSubnet = $NICInfo.IpSubnet
$ipGateWay = $NICInfo.DefaultIPGateway
$macAddress = $NICInfo.MACAddress
Write-Host "Network Card": $intIndex
Write-Host "Interface Name: $caption"
Write-Host "IP Addresses: $ipAddress"
Write-Host "Subnet Mask: $ipSubnet"
Write-Host "Default Gateway: $ipGateway"
Write-Host "MAC: $macAddress"
$intIndex += 1
}
" "
# Write-Host "Enumerating Software Installations..." -ForegroundColor Green
# " "
# Get-WmiObject -Class Win32_Product | Select-Object -property Name
Write-Host "Enumerating installed Services..." -ForegroundColor Green
Get-Service | Sort-Object status,displayname

The code that you posted is fine. It's something else that you are not showing that does not work.
Try this:
$script = #"
Write-Host "Enumerating installed Services..." -ForegroundColor Green
Get-Service | Sort-Object status,displayname
"#
$script | Set-Content ./test.ps1
./test.ps1
The above writes your two lines in a script file and then executes the script. As you would expect it produces desired output.
Update 1
Having seen the input, I can now reproduce the problem. Basically if you run this:
$a= Get-WmiObject -Class win32_volume -cn $s |
Select-Object #{LABEL='Comptuer';EXPRESSION={$s}},DriveLetter, Label,#{LABEL='Free Space (GB)';EXPRESSION={"{0:N2}" -f ($_.freespace/1GB)}}
$b = Get-Service | Sort-Object status,displayname
$a
$b
you will see that it does not quite work. What happening here is that by default Write-Output is used to process the results. Write-Output writes stuff in the success pipeline, and powershell does unwrapping of the arrays. Then, I'm guessing the output system can't cope with the fact that output from get-service and select-object are of different types (and because of unwrapping they end up in the same array).
If you change the last line of your script to
Get-Service | Sort-Object status,displayname | ft
it will work. However note, that if you are going to pass around the results of your script, you better format it (ft) at the very end right before displaying. Basically, once you piped it to ft there is rarely a good reason to pass it anywhere else but for output (display or file).
Update 2
This article explains, that powershell uses the first object in the stream to determine how to format all of them. This explains the behaviour that we are observing.

Related

How to store the username in a csv file before and after the change using Powershell - ($BeforeAccountChange - Works) $AfterChangeAccount - Does NOT

$complist = Get-Content "c:\scripts\computers.txt"
foreach($computer in $complist){
Write-Host "Checking on $computer" -ForegroundColor yellow
Write-host ""
$pingtest = Test-Connection -ComputerName $computer -Quiet -Count 1 -ErrorAction SilentlyContinue
if($pingtest){
Write-Host($computer + " is online") -ForegroundColor Green
Invoke-Command -Computername $computer {
Get-Service | Where-Object {$_.Name -eq "ontapavc"}
$service = Get-WmiObject win32_service -filter "name='ontapavc'"
$BeforeChangeAccount=$service.StartName
Write-Host ""
Write-Host "Logon Credentials for " -ForegroundColor cyan -NoNewline;Write-Host $service.DisplayName -NoNewline; Write-Host " prior to Script Change: "-ForegroundColor cyan -NoNewline;Write-Host $service.StartName
Write-Host ""
Write-Host "Setting default logon Credentials" -ForegroundColor yellow
SC.exe CONFIG "ontapavc" obj= Home\Tester password= "Testing"
$AfterChangeAccount=$service.StartName
Write-Host ""
Write-Host "Setting Recovery Options" -ForegroundColor yellow
SC.exe failure "ontapavc" reset= 60000 actions= restart/60000/restart/60000/reboot/60000
Write-Host ""
Write-Host "Stopping service " -ForegroundColor yellow -NoNewline; Write-Host $service.name
Get-Service | Where-Object {$_.Name -eq "ontapavc"} | Stop-Service -PassThru
Write-Host ""
Write-Host "Restarting service " -ForegroundColor yellow -NoNewline; Write-Host $service.name
Get-Service | Where-Object {$_.Name -eq "ontapavc"} | Start-Service -PassThru
Write-Host ""
Write-Host ""
Write-Host ""
}
Write-Host "Logon Credentials for " -ForegroundColor cyan -NoNewline;Write-Host $servicename -NoNewline; Write-Host " after Change:"-ForegroundColor cyan -NoNewline;Write-Host $afterchangeaccount
$Sample = Get-WmiObject -Query "select * from win32_service where name='ontapavc'" -ComputerName $computer | Select-Object #{Name = 'Time'; Expression = {(Get-Date -format s)}}, PSComputerName, Name,DisplayName, ServiceName, Status, #{Name = 'Username Prior to Change'; Expression = { ($BeforeChangeAccount = $service.StartName)}}, #{Name = 'Username After Change'; Expression = { ($AfterChangeAccount = $service.StartName)}}
$Sample | Export-Csv -Path c:\Temp\ServiceList_-$((Get-Date).ToString('MM-dd-yyyy')).csv -NoTypeInformation
}else{
Write-Host $computer "is not reachable" -ForegroundColor red
Write-host ""
}
}
The 2 variables mentioned live in a remote scope. Therefore, you need to bring them out of your Invoke-Command to be referenced in your local scope.
$complist = Get-Content "c:\scripts\computers.txt"
foreach($computer in $complist){
Write-Host "Checking on $computer" -ForegroundColor yellow
Write-host ""
$pingtest = Test-Connection -ComputerName $computer -Quiet -Count 1 -ErrorAction SilentlyContinue
if ($pingtest) {
Write-Host($computer + " is online") -ForegroundColor Green
Invoke-Command -Computername $computer {
Get-Service | Where-Object {$_.Name -eq "ontapavc"} | Write-Host
$service = Get-WmiObject win32_service -filter "name='ontapavc'"
$BeforeChangeAccount=$service.StartName
Write-Host ""
Write-Host "Logon Credentials for " -ForegroundColor cyan -NoNewline;Write-Host $service.DisplayName -NoNewline; Write-Host " prior to Script Change: "-ForegroundColor cyan -NoNewline;Write-Host $service.StartName
Write-Host ""
Write-Host "Setting default logon Credentials" -ForegroundColor yellow
SC.exe CONFIG "ontapavc" obj= Home\Tester password= "Testing"
$AfterChangeAccount=$service.StartName
Write-Host ""
Write-Host "Setting Recovery Options" -ForegroundColor yellow
SC.exe failure "ontapavc" reset= 60000 actions= restart/60000/restart/60000/reboot/60000
Write-Host ""
Write-Host "Stopping service " -ForegroundColor yellow -NoNewline; Write-Host $service.name
Get-Service | Where-Object {$_.Name -eq "ontapavc"} | Stop-Service -PassThru | Write-Host
Write-Host ""
Write-Host "Restarting service " -ForegroundColor yellow -NoNewline; Write-Host $service.name
Get-Service | Where-Object {$_.Name -eq "ontapavc"} | Start-Service -PassThru | Write-Host
Write-Host ""
Write-Host ""
Write-Host ""
[PSCustomObject]#{
Before = $BeforeChangeAccount
After = $AfterChangeAccount
}
} | Set-Variable changes
Write-Host "Logon Credentials for " -ForegroundColor cyan -NoNewline;Write-Host $servicename -NoNewline; Write-Host " after Change:"-ForegroundColor cyan -NoNewline;Write-Host $afterchangeaccount
$Sample = Get-WmiObject -Query "select * from win32_service where name='ontapavc'" -ComputerName $computer | Select-Object #{Name = 'Time'; Expression = {(Get-Date -format s)}}, PSComputerName, Name,DisplayName, ServiceName, Status, #{Name = 'Username Prior to Change'; Expression = { $changes.Before}}, #{Name = 'Username After Change'; Expression = { $changes.After}}
$Sample | Export-Csv -Path c:\Temp\ServiceList_-$((Get-Date).ToString('MM-dd-yyyy')).csv -NoTypeInformation
}else{
Write-Host $computer "is not reachable" -ForegroundColor red
Write-host ""
}
}
By not polluting the pipeline, you should be able to create a pscustomobject to hold the two outputs you're looking for.
[PSCustomObject]#{
Before = $BeforeChangeAccount
After = $AfterChangeAccount
}
Now you can save to a variable to reference later on in your calculated properties since $changes now holds a before and after property.

Powershell Menu

I am looking to have this menu that I have been frankensteining and learning powershell while doing so, I am a systems admin I and trying to learn PS and more networking to grow in career. Any edits and advice is much appreciated I just bought a ps book and youtubing a lot!
Function Menu {
Clear-Host
Do
{
Clear-Host
Write-Host -Object 'Please choose an option'
Write-Host -Object '**********************'
Write-Host -Object 'Scripts to run' -ForegroundColor Yellow
Write-Host -Object '**********************'
Write-Host -Object '1. Ping PC '
Write-Host -Object ''
Write-Host -Object '2. Restart ELP Desktops '
Write-Host -Object ''
Write-Host -Object '3. Restart NOVI Desktops '
Write-Host -Object ''
Write-Host -Object '4. Check PC Storage '
Write-Host -Object ''
Write-Host -Object 'Q. Quit'
Write-Host -Object $errout
$Menu = Read-Host -Prompt '(0-4 or Q to Quit)'
switch ($Menu)
{
1 {
$Computer = Read-Host Please Enter Host name
Get-WMIObject Win32_NetworkAdapterConfiguration -Computername $Computer | `
Where-Object {$_.IPEnabled -match "True"} | `
Select-Object -property DNSHostName,ServiceName,#{N="DNSServerSearchOrder";
E={"$($_.DNSServerSearchOrder)"}},
#{N='IPAddress';E={$_.IPAddress}},
#{N='DefaultIPGateway';E={$_.DefaultIPGateway}} | FT
pause
}
2
{
restart-computer -ComputerName ######## -force
}
3
{
restart-computer -ComputerName ######## -force
}
4
{
# Ask for computer name
$Computer = Read-Host "Please Enter Host name"
Get-WmiObject Win32_LogicalDisk -ComputerName $Computer -Filter DriveType=3 | Select-
Object DeviceID, FreeSpace, Size |pause
}
Q
{
Exit
}
default
{
$errout = 'Invalid option please try again........Try 0-4 or Q only'
}
}
}
until ($Menu -eq 'q')
}
# Launch The Menu
Menu

If/Else Help in Powershell

Running an IF/Else statement and if "false" I want it to run a search for the current NVIDIA driver and tell me the current version then stop the script. Tried a couple different things to no avail. Currently it is continuing the script and running the "Get-WmiObject" out of order in a subsequent function.
Function Namespace_Check
{ Write-Host "Checking available namepace" -ForegroundColor Green
if ((Get-CimInstance -namespace "root\cimv2" -ClassName __NAMESPACE).Name -match 'NV'){return}
else { return (Get-WmiObject Win32_PnPSignedDriver| select devicename, driverversion | where {$_.devicename -like "*nvidia*"})}
Write-Host "If Stopped, install latest NVIDIA driver from SWE"
Write-Host "Complete" -ForegroundColor Green
}
Here is the whole script, if there needs to be other changes to the logic
Function Namespace_Check
{ Write-Host "Checking available namepace" -ForegroundColor Green
Write-Host "Complete" -ForegroundColor Green
if ((Get-CimInstance -namespace "root\cimv2" -ClassName __NAMESPACE).Name -match 'NV'){return}
else {
exit (Get-WmiObject Win32_PnPSignedDriver| select devicename, driverversion | where {$_.devicename -like "*nvidia*"})
Write-Warning "Install latest NVIDIA driver from SWE"
Write-Host
}
}
Function InstallSWE
{
Write-Host "Installing SWE Icon..." -ForegroundColor Green
$ps = new-object System.Diagnostics.Process
$ps.StartInfo.FileName = "\\nt-iss-1\setools\xsetup.exe"
$ps.StartInfo.Arguments = " -Silent -NoPrompt -NoBanner"
Write-Host " Execute Software Express"
[Void]$ps.start()
$ps.WaitForExit()
Write-Host "Complete" -ForegroundColor Green
}
Function CheckNVIDIADriver
{
Write-Host "Checking NVIDIA Drivers..." -ForegroundColor Green
$productName = Get-WmiObject -namespace "root\cimv2\nv" -Class Gpu | Select -ExpandProperty productName
$driverVersion = Get-Wmiobject -namespace "root\cimv2\nv" -class System | Select -ExpandProperty verDisplayDriver | Select -ExpandProperty strValue
Write-Host " Product Name : $productName"
Write-Host " Video Driver Version: $driverVersion"
Write-Host "Complete" -ForegroundColor Green
}
Function SetNVIDIA3DGlobalPreset
{
Write-Host "Setting NVIDIA 3D Global Preset..." -ForegroundColor Green
$global3DPreset = "Dassault Systemes CATIA - compatible"
$profileManager = Get-WmiObject -namespace "root\cimv2\nv" -Class ProfileManager
"Change Global 3D Preset to $global3DPreset"
[void](Invoke-WmiMethod -Path $profileManager.__PATH -Name setCurrentProfile3D -ArgumentList $global3DPreset, $null)
Write-Host "Complete" -ForegroundColor Green
}
Function SetScreenSaver
{
Write-Host "Setting Screen Saver..." -ForegroundColor Green
$regkeypath = "HKCU:\Control Panel\Desktop"
$screensaver = "C:\Windows\SysWOW64\CORPOR~1.SCR"
Write-Host " Change Screen Saver to Corporate Screen Saver"
Set-ItemProperty -Path $regkeypath -Name "SCRNSAVE.EXE" -Value $screensaver
Write-Host "Complete" -ForegroundColor Green
}
Function ChangePowerSettings
{
Write-Host "Changing Power Settings..." -ForegroundColor Green
Write-Host " Disable Monitor Timeout"
powercfg -x -monitor-timeout-ac 10
powercfg -x -monitor-timeout-dc 10
Write-Host " Disable Disk Timeout"
powercfg -x -disk-timeout-ac 0
powercfg -x -disk-timeout-dc 0
Write-Host " Disable Standby Timeout"
powercfg -x -standby-timeout-ac 0
powercfg -x -standby-timeout-dc 0
Write-Host " Disable Hibernate and Hybrid Sleep"
powercfg -x -hibernate-timeout-ac 0
powercfg -x -hibernate-timeout-dc 0
powercfg -h off
Write-Host "Complete" -ForegroundColor Green
}
Function ChangeVirtualMemory
{
Write-Host "Changing Virtual Memory Settings..." -ForegroundColor Green
$mem = [Math]::Round((Get-WmiObject -Class Win32_ComputerSystem |Select -ExpandProperty TotalPhysicalMemory) / [Math]::pow(1024, 3))
$initialSize = 2048 * $mem
$maximumSize = 2 * $initialSize
Write-Host " Disable Automatic Managed Page File"
$System = Get-WmiObject Win32_ComputerSystem -EnableAllPrivileges
$System.AutomaticManagedPagefile = $False
[Void]$System.Put()
Write-Host " Set Page File Size (Initial Size: $initialSize MB / Maximum Size: $maximumSize MB)"
$PageFile = Get-WmiObject -class Win32_PageFileSetting
$PageFile.InitialSize = $initialSize
$PageFile.MaximumSize = $maximumSize
[Void]$PageFile.Put()
Write-Host "Complete" -ForegroundColor Green
}
Function EnableRDP
{
Write-Host "Enabling Remote Desktop and User..." -ForegroundColor Green
$computername = $(gc env:computername)
$RDP = Get-WmiObject -Class Win32_TerminalServiceSetting -Namespace root\CIMV2\TerminalServices
Write-Host " Enable Remote Desktop"
$result = $RDP.SetAllowTsConnections(1, 1)
Try
{
$user ="CAxILABRemoteUsers"
$domain ='NW'
$objUser = [ADSI]("WinNT://$domain/$user")
$objGroup = [ADSI]("WinNT://$computername/Remote Desktop Users")
Write-Host " Add Remote Desktop User $domain\$user"
$objGroup.PSBase.Invoke('Add',$objUser.PSBase.Path)
}
Catch
{
}
Write-Host "Complete" -ForegroundColor Green
}
Function CheckAdministrator
{
$user = [Security.Principal.WindowsIdentity]::GetCurrent();
(New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
}
# Filename: CAxILab_Final_Config.ps1
$pshost = get-host
$pswindow = $pshost.ui.rawui
$newsize = $pswindow.buffersize
$newsize.height = 999
$pswindow.buffersize = $newsize
$newsize = $pswindow.windowsize
#$newsize.height = 60
#$pswindow.windowsize = $newsize
$host.ui.RawUI.ForegroundColor = "White"
$isAdmin = CheckAdministrator
if ($isAdmin)
{
Namespace_Check
Write-Host
InstallSWE
Write-Host
CheckNVIDIADriver
Write-Host
SetNVIDIA3DGlobalPreset
Write-Host
SetScreenSaver
Write-Host
ChangePowerSettings
Write-Host
ChangeVirtualMemory
Write-Host
EnableRDP
Write-Host
}
else
{
Write-Warning "Administrator rights is required to run this script"
Write-Host
}
Write-Host "Press any key to continue ..."
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
# end of script
If you want the script stopped completely when the namespace is not found, change the function Namespace_Check into something like this:
Function Namespace_Check {
Write-Host "Checking available namepace" -ForegroundColor Green
if (!((Get-CimInstance -namespace "root\cimv2" -ClassName __NAMESPACE).Name -match 'NV')) {
# if we got here, the namespace is not found
# output the current version, then stop the script
$driver = Get-WmiObject Win32_PnPSignedDriver|
Select-Object devicename, driverversion |
Where-Object {$_.devicename -like "*nvidia*"}
Write-Host "If Stopped, install latest NVIDIA driver from SWE"
if ($driver) {
Write-Host "Current driver(s)" -ForegroundColor Yellow
$driver | Format-Table -AutoSize
}
else {
Write-Warning "No nvidia drivers found"
}
Write-Host "Script Complete" -ForegroundColor Green
# stop the script
exit
}
}
In your version you are trying to write to console after you have exited the function using a return statement. These lines will therefore never be executed.
Edit
Alternatively, you can have the function Namespace_Check return a value of $true of $false like this:
Function Namespace_Check {
Write-Host "Checking available namepace" -ForegroundColor Green
if (!((Get-CimInstance -namespace "root\cimv2" -ClassName __NAMESPACE).Name -match 'NV')) {
# if we got here, the namespace is not found
# output the current version, then stop the script
$driver = Get-WmiObject Win32_PnPSignedDriver|
Select-Object devicename, driverversion |
Where-Object {$_.devicename -like "*nvidia*"}
Write-Host "If Stopped, install latest NVIDIA driver from SWE"
if ($driver) {
Write-Host "Current driver(s)" -ForegroundColor Yellow
$driver | Format-Table -AutoSize
}
else {
Write-Warning "No nvidia drivers found"
}
Write-Host "Script Complete" -ForegroundColor Green
return $false
}
return $true
}
and in the main part of your script do
if ($isAdmin) {
if (Namespace_Check) {
Write-Host
InstallSWE
Write-Host
CheckNVIDIADriver
Write-Host
SetNVIDIA3DGlobalPreset
Write-Host
SetScreenSaver
Write-Host
ChangePowerSettings
Write-Host
ChangeVirtualMemory
Write-Host
EnableRDP
Write-Host
}
}
else {
Write-Warning "Administrator rights is required to run this script"
Write-Host
}
Write-Host "Press any key to continue ..."
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
# end of script
This will make the script end gracefully instead of when using the exit statement.

Disk cleanup using PowerShell

I am trying to write a script for cleaning disks. All works except running cleanmgr. Can someone advise?
$objShell = New-Object -ComObject Shell.Application
$objFolder = $objShell.Namespace(0xA)
$computername = Read-Host -Prompt 'Enter machine name'
foreach ($hosts in $computername) {
#$temp = get-ChildItem "env:\TEMP"
#$temp2 = $emp.Value
#$swtools = "c:\SWTOOLS\*"
$ccmcache = "\\$hosts\c$\Windows\ccmcache\*"
$temp = "\\$hosts\C$\Users\*****\AppData\Local\Temp\*"
#$WinTemp = "c:\Windows\Temp\*"
$FreespaceBefore = (Get-WmiObject -Class win32_logicaldisk -ComputerName $hosts -Filter "DeviceID='C:'" | select Freespace).FreeSpace/1GB
#Write-Output "Disk Space Before"
Write-Output "$FreespaceBefore"
Write-Host "Removing Junk files in $ccmcache on $hosts." -ForegroundColor Green
Remove-Item -Recurse $ccmcache -Force -Verbose
Write-Host "Removing Junk files in $temp on $hosts." -ForegroundColor DarkYellow
Remove-Item -Recurse $temp -Force -Verbose
Write-Host "Finally now , Running Windows disk Clean up Tool" -ForegroundColor Cyan
Invoke-Command -ComputerName pc -ScriptBlock {Start-Process cleanmgr.exe}
#Write-Output "Disk Space after"
#Write-Output "$diskspaceafter"
$([char]7)
Sleep 1
$([char]7)
Sleep 1
Write-Host "I finished the cleanup task,Succefully " -ForegroundColor Yellow
}
2# Running Disk Clean up Tool
write-Host "Finally now , Running Windows disk Clean up Tool" -ForegroundColor Cyan
cleanmgr /sagerun:1 /VERYLOWDISK | out-Null
$([char]7)
Sleep 1
$([char]7)
Sleep 1
I know this question is old but for anyone still looking...
This link could provide a couple options, like the one below
foreach ($computer in $computers){
if(!(Test-Connection -Cn $computer -BufferSize 16 -Count 1 -ea 0 -quiet))
{write-host "cannot reach $computer" -f red}
else {& \\$computer\C$\Windows\System32\cleanmgr.exe /sagerun:1}}

Is there any Faster method to do WMI query from Powershell ..?

Wrote a small script to find the number Multipaths from the windows servers using WMI query. It works well for the servers which can connect directly without any issue. But if one server is pingable but not able to reach through WMI script, it takes long time to return the error ( for example if a linux server hostname is present in the servers.txt list).. Can somebody help me to do the same in a faster way..?
$Servers = Get-Content .\Servers.txt
$ErrorActionPreference = ‘SilentlyContinue’
FOREACH ($Server in $Servers) {
Write-Host $Server -nonewline
if (test-connection -computername $Server -Count 1 -quiet) {
$Name = $null
$NoPath =$null
$MPIODisks =$null
$MPIODisks = Get-WmiObject -Namespace root\wmi -Class mpio_disk_info -ComputerName "$Server" |Select-Object "DriveInfo"
if ($MPIODisks -eq $Null) {
write-host "`t - Unable to connect" -fore "RED"
} else {
write-host ""
write-host "Drive Name `tNo.Path" -fore "yellow"
Foreach ($Disk in $MPIODisks) {
$mpiodrives = $disk.DriveInfo
foreach ($Drive in $mpiodrives) {
$Name = $Drive.Name
$NoPath = $Drive.Numberpaths
If ($NoPath -lt 4) {
Write-Host $Name `t -nonewline
write-host $NoPath -fore "Red"
} else {
Write-Host $Name `t -nonewline
write-host $NoPath -fore "Green"
}
}
}
}
write-host ""
} else {
write-host "`t- Unknown Host" -fore "Red"
write-host ""
}
}
There is a connect item for Get-WmiObject to add a timeout parameter. A workaround noted in that item is to just pipe your WMI command to Wait-Job and specify a timeout period in seconds.
As long as your on PS version 3.0 or higher, this should work for you:
Get-WmiObject win32_computersystem -ComputerName <hostname> -AsJob | Wait-Job -Timeout 10 | Receive-Job
As an alternative, you could ask all servers for the result at once by passing them all into the query and avoiding the slow loop querying one server at a time. I don't have any MPIO drives to test with, but it could look something like this (using Get-Ciminstance which takes a timeout parameter):
$servers = Get-Content .\Servers.txt
# Get data from all servers with timeout
$servers_ok = Get-CimInstance -computername $servers -Namespace root\wmi -Class mpio_disk_info -ErrorAction SilentlyContinue -OperationTimeoutSec 1 | group pscomputername
# Output which servers gave no result back
foreach($no_result in $($servers | where { $_ -NotIn $servers_ok.Name })) {
write-host "No result for $no_result" -ForegroundColor Red
}
# Loop over the results and output
foreach($server in $servers_ok) {
Write-Host $server.Name
foreach($mpiodisk in $server.group)  {
$mpiodrives = $mpiodisk.DriveInfo
foreach ($mpiodrive in $mpiodrives) {
$name = $mpiodrive.Name
$noPath = $mpiodrive.NumberPaths
If ($NoPath -lt 4) {
write-host $name `t -nonewline
write-host $noPath -fore "Red"
} else {
write-host $name `t -nonewline
write-host $noPath -fore "Green"
}
}
}
}