Get-WmiObject delay outcome when check C disk storage - powershell

Get-WmiObject delay outcome when check C disk storage.
When I input my computer name and type '1' to check the C disk storage, the first time won't return the outcome, and I need to type '1' again it will return both the first and second outcome.
However, if I test the function or the line Get-WMIObject separately, it works perfect.
Anyone have any idea what's going on here?
$ComputerNumber = (read-host "Provide computer number").trim()
function Show-Storage{
Get-WmiObject -Class win32_logicaldisk -Filter "DeviceID='C:'" -ComputerName $ComputerNumber|select PSComputerName,DeviceID,#{n='size(GB)';e={$_.size/1gb -as [int]}},#{n='Free(GB)';e={$_.freespace/1gb -as [int]}}
}
function Show-Menu
{
param (
[string]$Title = 'Computer Info'
)
Write-Host "================ $Title ================"
Write-Host ""
Write-Host "1: Press '1' to get Current Computer Usage"
Write-Host "2: Press '2' to delete Local User Profile"
Write-Host "Q: Press 'Q' to quit."
}
$a=1
While ($a -eq 1)
{
write-host ""
Show-Menu
write-host ""
if ($ComputerNumber -ne $null){
write-host "Selected Computer '$ComputerNumber'"
}
else{write-host "No Computer selected"}
$selection = Read-Host "Please make a selection"
switch($selection)
{
'1'{
write-host ""
Show-Storage
write-host ""
}
'2'{
delete-profile
}
'Q'{$a=0}
}
}
I just found another interesting thing, if I leave the line $result, the result will come before the "WMI end", but if I remove that line, the result will still comes after "WMI end"
Write-Host "WMI Start"
$result = Get-WmiObject -query "SELECT * FROM Win32_logicalDisk WHERE DeviceID = 'C:'" -ComputerName $PC
$result
$result |select PSComputerName,DeviceID,#{n='size(GB)';e={$_.size/1gb -as [int]}},#{n='Free(GB)';e={$_.freespace/1gb -as [int]}}
Write-Host "WMI End"
enter image description here

Found solution finally, use | Out-Host can fix this issue.
Reference:
Get-WMIObject returning multiple responses in a script, only one when run alone

Related

Adding new options causes issues

I have been able to create and frankenstein a menu to help me as IT support and am still learning powershell to read and write it proficiently but am confused why if I put more options I run into issues mainly at the end.
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 '5. Check all user adpw exp'
Write-Host -Object ''
Write-Host -Object 'Q. Quit'
Write-Host -Object $errout
$Menu = Read-Host -Prompt '(0-5 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
{
Invoke-Command -ComputerName (Read-Host -Prompt "Please Enter Host name") {Get-PSDrive | Where {$_.Free -gt 0}}
pause
}
5
{
get-aduser -filter * -properties passwordlastset, passwordneverexpires |ft Name, passwordlastset, Passwordneverexpires
pause
}
Q
{
Exit
}
default
{
$errout = 'Invalid option please try again........Try 0-5 or Q only'
}
}
}
until ($Menu -eq 'q')
}
# Launch The Menu
Menu

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

Subexpression printing out same strings? Powershell

I have this code which deletes User Profiles off a remote machine. The removal of profiles work just fine but, the Aesthetic of doing so doesn't. What do i mean?
I'm passing the user display names to an index and making a selection out of it, and that works fine in regards to assigning the proper names to the appropriate Index Number its associated to in C:\users.
The next line of code is it grabbing the selections i made, and running through them displaying the same name i did for the index, and then it goes off to delete the CIM instance.
So my question is, why is it not passing the subexpression $userinfo1 that is already made and not putting it into the next block of code, for example, the following works as in grabbing the proper Display Name and assigning it to the proper Number:
$menu = (get-childitem "\\$cn\c$\users" | sort LastWriteTime -Descending).Name
$userinfo1 = foreach ($user in $menu) {
Start-Sleep -Milliseconds 2
$userinfo = (net user $user /domain | Select-String "Full Name" -ErrorAction SilentlyContinue) -replace "Full Name ", "" 2>&1 | Out-String -Stream
if ($userinfo.Length -lt 4) {
"$user - NO DISPLAY NAME in ADUC" # output
}
else {
if ($LASTEXITCODE -eq 2) {
"$user - account not in ADUC" # output
}
else {
if ($LASTEXITCODE -eq 0){
$userinfo # output
}
}
}
}
Write-Warning "Ensure user profiles are no longer active and/or, have profiles be backed-up!"
Write-Host "RESULTS:" -BackgroundColor Black -ForegroundColor White
for ($i=0; $i -lt $userinfo1.Count; $i++) {
Write-Host "$($i): $($userinfo1[$i])"
} #END LIST OF POSSIBLE NAMES
Write-Host ""
Write-Host "For multiple users, seperate using a SPACE(1 2 3)"
$selection = Read-Host "ENTER THE NUMBER of the user(s) or Q to quit"
$selection = $selection -split " "
but, the next block doesn't associate the display name (that was captured in $userinfo1) with the number i select and it just continues to display the first display name with the rest of the profiles its reiterating through:
foreach($Profile in $menu[$selection]){
Write-Host "Deleting user: $(,$userinfo1[$selection]) `
ID:$Profile "}
Hopefully this makes sense, and if anyone can point me in the right direction id greatly appreciate it!
Heres the rest of the script, please feel free to use it as it does work for deleting the actual profile off the system and not just the files.
#Deletes a profile properly off remote machine. WARNING: DOES NOT BACK UP DATA! Use at your own peril. Delprofile
$cn = Read-Host -Prompt "Enter Computer Name"
$ping = Test-Connection -ComputerName $cn -Count 1 -Quiet
If($ping -eq $false){ Write-Host "Computer seems to be offline, please check name spelling." -ForegroundColor DarkYellow; Write-Host ""; &PFL-Delete } else {
$menu = (get-childitem "\\$cn\c$\users" | sort LastWriteTime -Descending).Name
$userinfo1 = foreach ($user in $menu) {
Start-Sleep -Milliseconds 2
$userinfo = (net user $user /domain | Select-String "Full Name" -ErrorAction SilentlyContinue) -replace "Full Name ", "" 2>&1 | Out-String -Stream
if ($userinfo.Length -lt 4) {
"$user - NO DISPLAY NAME in ADUC" # output
}
else {
if ($LASTEXITCODE -eq 2) {
"$user - account not in ADUC" # output
}
else {
if ($LASTEXITCODE -eq 0){
$userinfo # output
}
}
}
}
Write-Warning "Ensure user profiles are no longer active and/or, have profiles be backed-up!"
Write-Host "RESULTS:" -BackgroundColor Black -ForegroundColor White
for ($i=0; $i -lt $userinfo1.Count; $i++) {
Write-Host "$($i): $($userinfo1[$i])"
} #END LIST OF POSSIBLE NAMES
Write-Host ""
Write-Host "For multiple users, seperate using a SPACE(1 2 3)"
$selection = Read-Host "ENTER THE NUMBER of the user(s) or Q to quit"
$selection = $selection -split " "
foreach($Profile in $menu[$selection]){
Write-Host "Deleting user: $(,$userinfo1[$selection]) `
ID:$Profile "
$del = Get-CimInstance -ComputerName $cn -Class Win32_UserProfile | Where-Object { $_.LocalPath.split('\')[-1] -eq $Profile }
If($del -eq $null){Write-Warning "No CIM instance found on system, profile has been deleted but files persist. Delete manually!"} else{
Get-CimInstance -ComputerName $cn -Class Win32_UserProfile | Where-Object { $_.LocalPath.split('\')[-1] -eq $Profile } | Remove-CimInstance -WhatIf
Write-Host "user profile has been deleted" -ForegroundColor Red
Write-Host ""}
}
}
#CountPs $cn
12/31/2020 - EDIT:
Here is the finished result:
Function Delete-PFL{
#Deletes a profile properly off remote machine. WARNING: DOES NOT BACK UP DATA! Use at your own peril. Delprofile
$cn = Read-Host -Prompt "Enter Computer Name"
$ping = Test-Connection -ComputerName $cn -Count 1 -Quiet
If($ping -eq $false){ Write-Host "Computer seems to be offline, please check name spelling." -ForegroundColor DarkYellow; Write-Host ""; &Delete-PFL } else {
$menu = (get-childitem "\\$cn\c$\users" | sort LastWriteTime -Descending).Name
$userinfo1 = foreach ($user in $menu) {
Start-Sleep -Milliseconds 2
$userinfo = (net user $user /domain | Select-String "Full Name" -ErrorAction SilentlyContinue) -replace "Full Name ", "" 2>&1 | Out-String -Stream
if ($userinfo.Length -lt 4) {
"$user - NO DISPLAY NAME in ADUC" # output
}
else {
if ($LASTEXITCODE -eq 2) {
"$user - ACCOUNT NOT in ADUC" # output
}
else {
if ($LASTEXITCODE -eq 0){
$userinfo # output
}
}
}
}
Write-Warning "Ensure user profiles are no longer active and/or, have profiles be backed-up!"
Write-Host "RESULTS:" -BackgroundColor Black -ForegroundColor White
for ($i=0; $i -lt $userinfo1.Count; $i++) {
Write-Host "$($i): $($userinfo1[$i])"
} #END LIST OF POSSIBLE NAMES
Write-Host ""
Write-Host "For multiple users, seperate using a SPACE(1 2 3)"
$selection = Read-Host "ENTER THE NUMBER of the user(s) or Q to quit"
$selection = $selection -split " "
foreach($index in $selection) {
$Profile = $menu[$index]
Write-Host "Deleting user: $($userinfo1[$index]) `
ID:$Profile "
$del = Get-CimInstance -ComputerName $cn -Class Win32_UserProfile | Where-Object { $_.LocalPath.split('\')[-1] -eq $Profile }
If($del -eq $null){Write-Warning "No CIM instance found on system, profile has been deleted but files persist."
Write-Host "Attempting to delete files, please wait. . ."
Remove-Item -Path "\\$cn\c$\users\$Profile" -Force -WhatIf
Write-Host ""
Start-Sleep -Seconds 2
Write-Host "Checking if Files are still there. . ."
$TestPath = Test-Path -Path "\\$cn\c$\users\$Profile"
If($TestPath -eq $false){ Write-Host "Profile Files have been deleted. `
Continuing. . . ." -ForegroundColor Green
}
} else{
Get-CimInstance -ComputerName $cn -Class Win32_UserProfile | Where-Object { $_.LocalPath.split('\')[-1] -eq $Profile } | Remove-CimInstance -WhatIf
Write-Host "user profile has been deleted" -ForegroundColor Red
Write-Host ""
}
}
}
#CountPs $cn
}
Remember to remove the -whatif parameter. Enjoy!
$selection is an array of indices, so in your foreach loop you must refer to the single index at hand, not to $selection as a whole, to get the desired display output.
The conceptually clearest approach is probably to iterate over the indices contained in $selection:
foreach($index in $selection) {
$Profile = $menu[$index]
Write-Host "Deleting user: $($userinfo1[$index]) `
EDIPI:$Profile "
# ...
}

Powershell Script outputs are merged instead of separated individually

I made this script to ping a computer name and if it's pingable, to return the username of the logged on user and if the user of the script so desires, a list of all the installed programs and a list of the installed printers the user is using.
When I run the script it returns the username and requires the users' input if they want to see the installed programs, the user answers Y or N. It asks the user afterwards if they want to the list of printers.
The script then gives an output of both the list of programs & printers as one answer.
My problem is that I would like the script to ask if the user wants the programs list, then to output the programs list, then prompt if the user wants the printers list, then output the printer list.
I have no idea how to go about this and have searched and experimented and have found no solution.
Any help or advice would be greatly appreciated :)
Apologies for the long post
# This script shows who is currently logged on to a machine
$PCNAME = Read-Host "Please enter computer name"
Write-Host "Pinging computer name..."
# If the computer responds to ping then the user name will be displayed
If (Test-Connection -ComputerName $PCNAME -Quiet)
{
$User = Get-WmiObject Win32_ComputerSystem -ComputerName $PCNAME | Select-Object -ExpandProperty UserName
$Time = Get-Date -DisplayHint Time
Write-Host ""
$CurUser = Write-Host "The current user logged in to $PCNAME is $User at $Time" -ForegroundColor Green
Write-Host ""
}
#PROGRAMS
$Programs = Read-Host "Would you like to see what programs $User has installed? Enter Y or N"
If ($Programs -eq "Y") {
Write-Host ""
Write-Host "Retrieving list of installed programs..."
Write-Host ""
Get-WmiObject -ComputerName $PCNAME -Class Win32_Product | sort-object Name | select Name
}
ElseIf ($Programs -ne "Y" -and $Programs -eq "N") {
Write-Host ""
Write-Host "Will not retrieve list of installed programs."
}
#PRINTERS
$Printers = Read-Host "Would you like to see the pinters that $User is using? Enter Y or N"
If ($Printers -eq "Y") {
Write-Host ""
Write-Host "Getting printers..."
Write-Host ""
# Collect port names and host addresses into hash table
$hostAddresses = #{}
Get-WmiObject Win32_TCPIPPrinterPort -ComputerName $PCNAME | ForEach-Object {
$hostAddresses.Add($_.Name, $_.HostAddress)
}
Get-WmiObject Win32_Printer -ComputerName $PCNAME | ForEach-Object {
New-Object PSObject -Property #{
"Name" = $_.Name
"DriverName" = $_.DriverName
"HostAddress" = $hostAddresses[$_.PortName]
}
}
}
ElseIf ($Printers -ne "Y" -and $Printers -eq "N") {
Write-Host ""
Write-Host "Could not get printers"
Write-Host ""
}
Else
{
Write-Host ""
Write-Host "Could not ping $PCNAME at $Time" -ForegroundColor DarkCyan
}
Write-Host ""
#$EndPrompt = ( Read-Host -Prompt "Press Enter to finish" )
There's better ways of doing this overall, but the simplest way to add this is:
#PROGRAMS
$Programs = Read-Host "Would you like to see what programs $User has installed? Enter Y or N"
If ($Programs -eq "Y") {
Write-Host ""
Write-Host "Retrieving list of installed programs..."
Write-Host ""
$Installed = Get-WmiObject -ComputerName $PCNAME -Class Win32_Product | sort-object Name | select Name
$Installed | Out-Host
}
ElseIf ($Programs -ne "Y" -and $Programs -eq "N") {
Write-Host ""
Write-Host "Will not retrieve list of installed programs."
}

Get-Service in a Powershell Script

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.