Powershell outputting info into text file but not into output pane - powershell

got a script here which I require the results that export into the text file to also show in the output pane at the bottom. Can anyone help please?
The results I've currently got is that it only shows the Make and model of the machine but not the others from Domain all the way to memory left in GB. I want it all to show on the output pane at the bottom and also to save in a text file which saves and opens straight away.
Please note: The file opens with the data in but the main issue is that it doesn't show in the output pane. Here is the script:
Clear-Host
Write-Host "Setting Execution Policy to Remote Signed..." -ForegroundColor Yellow
Set-ExecutionPolicy RemoteSigned -Force
Write-Host "Your execution policy is set to:" -ForegroundColor Cyan
Get-ExecutionPolicy
Start-Sleep -s 3
Clear-Host
Write-Host "Generating computer statistics..." -ForegroundColor Yellow
Write-Host " "
Start-Sleep -s 2
function systemstats {
Write-Host "Manufacturer:" -ForegroundColor Cyan
Write-Host "$($m.Manufacturer)" -ForegroundColor Yellow
Write-Host "Model:" -ForegroundColor Cyan
Write-Host "$($m.Model)" -ForegroundColor Yellow
Write-Host "Domain:" -ForegroundColor Cyan
$env:USERDOMAIN
Write-Host "Computer Name:" -ForegroundColor Cyan
$env:COMPUTERNAME
Write-Host "Operating System & Location:" -ForegroundColor Cyan
(Get-WmiObject Win32_OperatingSystem).name
Write-Host "OS Architecture:" -ForegroundColor Cyan
if ((Get-WmiObject win32_operatingsystem | select osarchitecture).osarchitecture -eq "64-bit")
{
Write "64-bit OS"
}
else
{
Write "32-bit OS"
}
Write-Host "OS Build:" -ForegroundColor Cyan
(Get-CimInstance Win32_OperatingSystem).version
Write-Host "Version:" -ForegroundColor Cyan
(Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ReleaseID).ReleaseID
Write-Host "Current IP Address:" -ForegroundColor Cyan
Ipconfig | Select-String IPv4
Write-Host "Calculating RAM installed in MB:" -ForegroundColor Cyan
(systeminfo | Select-String 'Total Physical Memory:').ToString().Split(':')[1].Trim()
$m = (Get-WmiObject -Class Win32_ComputerSystem -Property * |
Select-Object -Property Manufacturer, Model)
Write-Host "Disk Space in GB:" -ForegroundColor Cyan
gwmi win32_logicaldisk | Format-Table DeviceId, MediaType, #{n="Size";e={[math]::Round($_.Size/1GB,2)}},#{n="FreeSpace";e={[math]::Round($_.FreeSpace/1GB,2)}}
}
$result=(systemstats)
$result | Out-File "C:\Users\brendan.hargate\Desktop\test.txt"
Invoke-Item "C:\Users\brendan.hargate\Desktop\test.txt"

Use Tee-Object instead of Out-File:
$result | Tee-Object -FilePath "C:\Users\brendan.hargate\Desktop\test.txt"
Tee-Object (inspired by tee), will duplicate the input stream - one copy is passed on down the pipeline (which in your case will end up in the command pane), the other is written to a variable or a file (like in the above example)

Your systemstats function in part uses Write-Host which operates outside of PowerShell's (success) output stream.
Write-Host output cannot be captured (PSv4) / is by default not captured (PSv5+) in variables or output files. As the name suggests, Write-Host writes to the host UI (the console), and is not meant to output data - that's what Write-Output and its alias, Write, as well as implicit output (e.g., $env:USERDOMAIN by itself) are for.
A variable assignment such as $result = ... only captures (success) output-stream output, i.e., the implicit output and the output from the Write (a.k.a. Write-Output) command. By contrast, your Write-Host commands printed straight to the console.
Given that you sent $result to a file - without also printing it to the console - the net effect was that only the Write-Host output appeared in the console.
The solution therefore has two components:
Modify your function to only use implicit output (Write-Output output) in order to produce data output.
Then use Tee-Object to print to both the console (via the success output stream) and a file, as suggested in Mathias R. Jessen's helpful answer.
As an aside, in PSv5+, you could get away with the following (although it is ill-advised), based on the ability to capture Write-Host output - now a virtual alias of Write-Information - via the newly introduced output stream number 6:
systemstats 6>&1 | # PSv5+: redirect the information stream to the (success) output stream.
Tee-Object -FilePath "$([Environment]::GetFolderPath('Desktop'))\text.txt"

Related

Physical memory check on client systems (Available memory slots and type of memory) using Powershell

I am trying to find a way to get an inventory of the installed physical memory, on multiple workstations. Someone was gracious enough to post a great script, on this question here...
From a previous question
That works beautifully and it is exactly what I am looking for, however I would like to be able to run this on several workstations (about 150) and running this one at a time is not exactly feasible. The "." being the system, in this case I am using that as the example, my question is where would I be able to insert the Get-Content statement so that it can run against the systems in question.
Here is the script code
[Cmdletbinding()]
Param(
[string]$Computername = "."
)
cls
$PhysicalMemory = Get-WmiObject -class "win32_physicalmemory" -namespace "root\CIMV2" -ComputerName $Computername
Write-Host "Computer Name:" $Computername -ForegroundColor Yellow
Write-Host "Memory Modules:" -ForegroundColor Green
$PhysicalMemory | Format-Table Tag,BankLabel,#{n="Capacity(GB)";e={$_.Capacity/1GB}},Manufacturer,PartNumber,Speed -AutoSize
Write-Host "Total Memory:" -ForegroundColor Green
Write-Host "$((($PhysicalMemory).Capacity | Measure-Object -Sum).Sum/1GB)GB"
$TotalSlots = ((Get-WmiObject -Class "win32_PhysicalMemoryArray" -namespace "root\CIMV2" -ComputerName $Computername).MemoryDevices | Measure-Object -Sum).Sum
Write-Host "`nTotal Memory Slots:" -ForegroundColor Green
Write-Host $TotalSlots
$UsedSlots = (($PhysicalMemory) | Measure-Object).Count
Write-Host "`nUsed Memory Slots:" -ForegroundColor Green
Write-Host $UsedSlots
If($UsedSlots -eq $TotalSlots)
{
Write-Host "All memory slots are in use. No available slots!" -ForegroundColor Yellow
}

powershell catch export to csv not working

I'm writing a script that is fed a .csv and tries to make an operation and then catches into a seperate .csv but for some reason I cant seem to feed the catch info into the csv. I get the error, "Export-csv : Cannot process argument because the value of argument "name" is not valid. Change the value of the "name" argument and run the operation again."
I appreciate any input from the brains.
#imports a csv and does somthing with the data. The columns in the csv are specified by the $($_.'columnName')
Import-Csv -Path 'PathToMyCSV.csv' | ForEach-Object{
#Print associated User
Write-Host "$($_.ModifiedEmail)" -ForegroundColor Yellow -NoNewline;
Write-Host " is the user's email prefix, " -NoNewline
#Print PC name to be moved
Write-Host "SD-LT-$($_.PCName)" -ForegroundColor Yellow -NoNewline;
Write-Host " is the PC they use, and " -NoNewline
#Print The OU the computer is moving to
Write-Host "$($_.OU)" -ForegroundColor Yellow -NoNewline;
Write-Host "is the OU the computer needs to go in!"
$pcname = "SD-LT-$($_.PCName)"
Try {
Get-ADComputer SD-LT-$($_.PCName) | Move-ADObject -TargetPath $($_.OU)
}
Catch {
Write-Host $_ -ForegroundColor Magenta
$pcname | Export-csv -Path 'PathToAnotherCSV.csv' -Append -Force
}
}
Try creating a PSCustomObject.
[PSCustomObject]#{'pcname'=$pcname} | Export-csv -Path 'PathToAnotherCSV.csv' -Append -Force

the first line output nothing in powershell

i try output parameter value in PowerShell, but it output nothing for the first time.
i have to try multiple times and it always succeeds after the first output.
does anyone know the problem?
here is the code test.ps1:
Get-Content D:/Config.txt | Foreach-Object{
$var = $_.Split('=')
New-Variable -Name $var[0] -Value $var[1]
}
Write-Host $DeskTopPath -BackgroundColor black
Write-Host $DeskTopPath -BackgroundColor green
Write-Host $DeskTopPath -BackgroundColor blue
Config.txt
DeskTopPath=D:\Users\Test\Desktop
my output
D:\Users\Test\Desktop
D:\Users\Test\Desktop
my PowerShell version: 5.1.14393.3471
Write-Host writes to the console immediately. It doesn’t wait for or care about what the pipeline is processing. It is simply executing too fast before your variable is created. You either need to add a sleep or delay or don’t use Write-Host.
Get-Content D:/Config.txt | Foreach-Object{
$var = $_.Split('=')
New-Variable -Name $var[0] -Value $var[1]
}
Start-Sleep -m 200
Write-Host $DeskTopPath -BackgroundColor black
Write-Host $DeskTopPath -BackgroundColor green
Write-Host $DeskTopPath -BackgroundColor blue
This isn't reproducible for everyone because of the number of variables involved in running PowerShell code. It will have to be trial and error.

Multithread PowerShell script

I have a PowerShell script that checks if a file is present in a folder. The problem is: This script works as it should, but it's very slowly. I must check 10K Pcs for a statistic / day.
I want to use Invoke-Command, but I can't use it because not all clients have enabled WinRM.
Is it possible to make this script multithread without WinRM?
Here is my code:
function Show-Menu {
param (
[string]$Title = 'Debug'
)
cls
Write-Host "================ $Title ================"
Write-Host "Ziel Clients werden in der Datei C:\temp\srv.txt angegeben!" -ForegroundColor Red
Write-Host "1: Detailansicht alle Clients" -ForegroundColor Green
Write-Host "2: Today Crash" -ForegroundColor Green
Write-Host "3: Detailansich einzelner Client" -ForegroundColor Green
Write-Host "Q: 'Q' zum beenden."
Write-Host "Script wird ausgefuehrt als:"
whoami
}
do {
Show-Menu
$input = Read-Host "Nummer angeben"
switch ($input) {
'1' {
cls
Write-Host "Detailansicht alle Clients"
$computers = Get-Content C:\temp\srv.txt
foreach ($computer in $computers) {
Write-Host -foregroundcolor "green" "Verarbeite $computer..."
if ( ! (Test-Connection $computer -Count 1 -Quiet)) {
Write-Host -foregroundcolor "red" "$computer ist offline"
continue
}
$path = Test-Path "\\$computer\c$\Program Files\Oracle\Runtime\BIN\ifrun60_*" -Include *dump*
Get-Item "\\$computer\c$\Program Files\Oracle\Runtime\BIN\ifrun60_*"
If ($path -eq $true ) { Write-Host $computer 'Dumps are present' }
Else { Write-Host $computer 'Dumps are not present' }
pause
}
}
'2' {
cls
Write-Host "Today Crash"
$computers = Get-Content C:\temp\srv.txt
foreach ($computer in $computers) {
Write-Host -foregroundcolor "green" "Verarbeite $computer..."
if ( ! (Test-Connection $computer -Count 1 -Quiet)) {
Write-Host -foregroundcolor "red" "$computer ist offline"
continue
}
$result = Get-ChildItem -Path "\\$computer\c$\Program Files\Oracle\Runtime\BIN\ifrun60_*" | Where-Object { $_.LastWriteTime -ge (Get-Date).Date }
}
$result | Out-GridView
}
'3' {
cls
Write-Host "Detailansich einzelner Client"
$computer = Read-Host -Prompt 'Client angeben'
$result = Get-ChildItem -Path "\\$computer\c$\Program Files\Oracle\Runtime\BIN\ifrun60_*"
$result | Out-GridView
}
}
}
until ($input -eq 'q')
While background jobs - started via Start-Job - do permit running in parallel, they run in child processes, and are therefore both resource-intensive and slow; furthermore, you cannot throttle their use, i.e. you cannot (directly) control how many child process at most are permitted to run simultaneously
Thread jobs, by contrast, run as threads in-process and therefore require fewer resources and are much faster than child-process-based background jobs; furthermore, throttling (limiting the number of threads permitted to run simultaneously) is supported.
Thread jobs are started via the Start-ThreadJob cmdlet, which comes with PowerShell [Core] v6+ and in Windows PowerShell can be installed on demand with, e.g., Install-Module ThreadJob -Scope CurrentUser.
You simply call Start-ThreadJob instead of Start-Job, and use the standard *-Job cmdlets to manage such thread jobs - the same way you'd manage a Start-Job-launched background job.
In the simplest case, you can simply wait for all threads to complete:
# PowerShell [Core] 6+
# Windows PowerShell with the ThreadJob module installed.
Get-Content C:\temp\srv.txt | ForEach-Object {
$computer = $_
Start-ThreadJob { # create a thread job and output an object representing it
Write-Host -ForegroundColor Green "Processing $using:computer..."
# ...
Get-Item "\\$using:computer\c$\Program Files\Oracle\Runtime\BIN\ifrun60_*"
# ...
}
} | Receive-Job -Wait -AutoRemoveJob
Note the use of the $using: scope specifier, which is needed to access the caller's $computer value; this requirement applies equally to background jobs, thread jobs, and remoting.
By default, up to 5 threads are allowed to run simultaneously; you can use the -ThrottleLimit parameter to modify this value, but note that increasing this value beyond what your hardware can support can actually slow things down.
Output sequencing isn't guaranteed; that is, the outputs aren't guaranteed to correspond to the order in which the computer names were specified.
In PowerShell 7+, there's an even easier way to run threads in parallel, via ForEach-Object's
-Parallel parameter:
# PowerShell 7+
Get-Content C:\temp\srv.txt | ForEach-Object -Parallel {
Write-Host -foregroundcolor Green "Processing $_..."
# ...
Get-Item "\\$_\c$\Program Files\Oracle\Runtime\BIN\ifrun60_*"
# ...
}
The comments above regarding output sequencing and throttling apply equally here, but note that the computer names are now provided as input via the pipeline, so the usual automatic $_ variable can be used inside the thread script block.

Export-Csv multiple forloop results

I have multiple forloops running with different variables pulling from .txt files. I want to export this all into a single csv file while having it look just like it does in powershell. Attached is what I get for powershell output and I would like to see the first write-host as a header in excel, followed by server name in column 1 and UP or DOWN in column 2 beneath it.
Powershell
Write-Host "Starting SVR2000MS" -ForegroundColor Yellow
$servers = Get-Content C:\Users\username\Desktop\subfolder\SVR2000.txt
foreach($server in $servers){
if (Test-Connection -ComputerName $server -Count 1 -ErrorAction SilentlyContinue) {
Write-Host "$server, UP" -ForegroundColor Green
}
else{
Write-Host "$server, DOWN" -ForegroundColor Red
}
}
Write-Host "Starting SVR2003DC" -ForegroundColor Yellow
$servers = Get-Content C:\Users\username\Desktop\subfolder\SVR2003.txt
foreach($server in $servers){
if (Test-Connection -ComputerName $server -Count 1 -ErrorAction SilentlyContinue) {
Write-Host "$server, UP" -ForegroundColor Green
}
else{
Write-Host "$server, DOWN" -ForegroundColor Red
}
}
Simple way:
You just print it and put it in a file
Instead of Write-Host ..., do:
"$server,UP" | Out-File test.csv -append
You can have more elaborate options by using objects, but it may be overkill for your needs.
If you want a clean file, you need to delete it at the beginning, because of -append.
BTW, no space after comma in a CSV :)
Edit:
Write-Host writes specifically ... to the host, i.e. the console, so you cannot redirect it elsewhere.