What is the difference between Write-Host and Write-Output in PowerShell?
Like...
Write-Host "Hello World";
Write-Output "Hello World";
In a nutshell, Write-Host writes to the console itself. Think of it as a MsgBox in VBScript. Write-Output, on the other hand, writes to the pipeline, so the next command can accept it as its input. You are not required to use Write-Output in order to write objects, as Write-Output is implicitly called for you.
PS> Get-Service
would be the same as:
PS> Get-Service | Write-Output
Write-Output sends the output to the pipeline. From there it can be piped to another cmdlet or assigned to a variable.
Write-Host sends it directly to the console.
$a = 'Testing Write-OutPut' | Write-Output
$b = 'Testing Write-Host' | Write-Host
Get-Variable a,b
Outputs:
Testing Write-Host
Name Value
---- -----
a Testing Write-OutPut
b
If you don't tell Powershell what to do with the output to the pipeline by assigning it to a variable or piping it to anoher command, then it gets sent to out-default, which is normally the console so the end result appears the same.
Write-Output sends the data as an object through the pipeline. In the Questions example it will just pass a string.
Write-Host is host dependent. In the console Write-Host is essentially doing [console]::WriteLine.
See this for more info.
Another difference between Write-Host and Write-Output:
Write-Host displays the message on the screen, but it does not write it to the log
Write-Output writes a message to the log, but it does not display it on the screen.
And Write-Host is considered as harmful. You can see a detailed explanation in Write-Host Considered Harmful.
One more thing about Write-Host vs Write-Output: inline String concatenation may not work as expected.
$sampleText = "World"
Write-Host "Hello" $sampleText
returns
Hello World
but
$sampleText = "World"
Write-Output "Hello" $sampleText
returns
Hello
World
This would encourage Write-Output with a variable (and use of concatenation) holding the entire string at once.
$hw = "Hello " + $sampleText
Write-Output $hw
You can understand the difference between the two cmds with below example:
Write-host "msgtxt" | Get-Service
On running above, you will get output as "msgtxt"
Write-output "msgtxt" | Get-Service
On running above, you will receive an error since msgtxt is not the name of any service.( In ideal condition) (Since you are writing it to a pipeline and it is being passed as input to Get-Service)
Related
I need your help
I need to print an logic condition in the specifc PowerShell output command.
Get-ItemProperty -Path 'HKLM:SOFTWARE\Policies\Microsoft\WindowsNT\TerminalServices' -Name fDisableCdm | Select fDisableCdm
I wrote a little script for test, but in my script I made a own conditional output. But I want print that what value have inside registry key and not print an own condition.
My script
if ($process=Get-ItemProperty -Path 'HKLM:SOFTWARE\Policies\Microsoft\WindowsNT\TerminalServices' -Name fDisableCdm -ErrorAction SilentlyContinue) {write-host "1"} else {write-host "0"}
You can help me ?
I waiting for help and tanks for all !
$regKey = "HKLM:SOFTWARE\Policies\Microsoft\WindowsNT\Terminal Services"
$regValue = 'fDisableCdm'
Try {
$process=Get-ItemProperty -Path $regKey -Name $regValue -ErrorAction Stop
Write-Output (-join($regValue,": ",$process.$regValue))
}
Catch {
Write-Output "There was an error: $($PSItem.ToString())"
}
You will need to check to see if your registry key for Terminal Services has a space or not. Mine has a space.
Otherwise, this script allows you to set the two variables at the beginning of the script, performs the requested lookup and, if no error occurs, outputs the requested information.
In the event of an error, the script outputs an appropriate error message.
Reference for meaningful error handling:
https://learn.microsoft.com/en-us/powershell/scripting/learn/deep-dives/everything-about-exceptions?view=powershell-7.1
Needed to change my code from direct call to Start-Job precedure because of timeouts caused by Symantec Antivirus (SEP) v14, making my script hanging.
this snap was working fine so long:
$updateDaten = Get-HotFix -computername "myserver" | % { $_.psbase.properties["installedOn"].Value } | Group-Object | select-object Name
The change to a start-job preocedure completely messes up the resulting object. im googling and testing for two days now but cannot find out what's so complicatet in dealing with job objects:
function Get-HotfixesListAsJob($computer, $timeout){
$job = Start-Job { param($c) Get-HotFix -computername $c |
% { $_.psbase.properties["installedOn"].Value } | Group-Object
} -ArgumentList $computer
Wait-Job $job -Timeout $timeout
Stop-Job $job
Receive-Job $job
Remove-Job $job
}
$updateDaten = Get-HotfixesListAsJob -computer "myserver" -timeout 80
However I am not able to get the same result back using Receive-Job. I Always get some wired job-object and I am not able to just extract the data as it was before. Why is the result so completely different? is it possible to get just the data back in an object as it was before instead of a job object?
btw. this interesting article did not solve my problem:
https://learn-powershell.net/2014/06/27/quick-hits-did-i-really-lose-my-output-with-receive-job-by-not-usingkeep/
Thanks for your answers in advance
The issue what you are having is not because of the code. Its because Start-job or any PS Job session, basically, will have all the details, properties related to that job.
So, I can see in the first case you have done a grouping and finally selecting only the name which is not there in the later case.
So I would suggest you to add that to the Function also.
One more thing , Wait-job will also output the value in the console. Either redirect or pipe it to null in order to avoid that.
You can also receive the job using receive-job with the job id or the name. I think that will be better. Just check the status of the job; Once done receive it.
I print outputs like this in my code, but I was told that my outputs needs to be in text(not object). Can somebody explain to me what it means and whats wrong in my code? Thanks.
Write-Output "ALL INSTALLED WINDOWS FEATURES:"
Write-Verbose -Message "Searching installed features..." -Verbose
$obj=Get-WindowsFeature | Where-Object {$_.Installed} | Select-Object Name, InstallState | Format-Table -AutoSize
Write-Output $obj
Write-Output "OPERATING SYSTEM INFO:"
Write-Verbose -Message "Searching operating system info..." -Verbose
$opInfo=Get-CimInstance Win32_OperatingSystem | Select-Object Version, Caption, InstallDate, LastBootUpTime, TotalVirtualMemorySize , SystemDirectory | FL
Write-Output $opInfo
There's nothing technically wrong with your code but personally I would change Write-Output "OPERATING SYSTEM INFO:" to a Write-Verbose, having that header in the output will make working with the results of your function in other parts of the code. However returning the object opInfo rather than a collection of strings is absolutely correct and the only reason someone would be telling you not to is if the code they intend what you are creating to interact with is either written incorrectly or written in an older scripting language like VBS, or if they are just not aware the preference for objects in Powershell development.
I have a beginner's knowledge in scripting and programming and have a set of PowerShell commands that I am having issues with figuring out how to turn it into a script.
I can successfully run the following remote commands from my Windows 7 machine by running the Exchange 2007 PowerShell console as my domain administrator account and then running the following commands to pass the commands to the Exchange 2013 hybrid server for use with Office 365:
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://hybridexch2013.contoso.com/PowerShell/ -Authentication Kerberos
Import-PSSession $Session
Enable-RemoteMailbox jame.doe#contoso.com -RemoteRoutingAddress jane.doe#contosoinc.mail.onmicrosoft.com
The more I look into this I don't know that I am making progress. See below for how my logic is working in my head on this. I understand this is incorrect and incomplete. I have commented out a function I had earlier but wasn't sure if I was doing it correct or if it was needed at all.
param($enableMailbox)
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://hybridexch2013.contoso.com/PowerShell/ -Authentication Kerberos
Import-PSSession $Session -AllowClobber
$fname = Read-Host "What is the user's first name?"
$lname = Read-Host "What is the user's last name?"
#function Func($enableMailbox)
#{
$enableMailbox = "Enable-RemoteMailbox $fname.$lname#contoso.com -RemoteRoutingAddress $fname.$lname#contosoinc.mail.onmicrosoft.com"
#}
#Func $enableMailbox
Write-Host $enableMailbox
I also find that if I manually run:
Enable-RemoteMailbox $fname.$lname#contoso.com -RemoteRoutingAddress $fname.$lname#contosoinc.mail.onmicrosoft.com
I get nothing. So I am not even understanding how you pass variables to the string to run the command correctly. Even if I run:
$fname = "Jane"
$lname = "Doe"
$enableMailbox = "Enable-RemoteMailbox $fname.$lname#contoso.com -RemoteRoutingAddress $fname.$lname#contosoinc.mail.onmicrosoft.com"
Write-Host $enableMailbox
I get no results.
I was trying to understand the param function using help from these pages: Powershell script with params *and* functions
Passing a variable to a powershell script via command line
https://devcentral.f5.com/blogs/us/powershell-abcs-p-is-for-parameters
http://www.experts-exchange.com/Programming/Languages/Scripting/Powershell/Q_27900846.html
But I am finding the param function difficult to understand and not sure I am even going in the right direction here. So far the only thing that seems to work is connecting to the PowerShell remotely.
Please help if I am am to be helped with this one and lack of my abilities here.
Param Function in short...
Function Write-Something
{
Param($InputText)
Write-Host $InputText
}
Write-Something Hello
Result is: Hello
Use Param Section to add Parameters to your Function like in the example above,
So for your Script:
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://hybridexch2013.contoso.com/PowerShell/ -Authentication Kerberos
Import-PSSession $Session -AllowClobber
Function Enable-MBX
{
Param($Fname,$Lname)
Enable-RemoteMailbox "$Fname $Lname" -RemoteRoutingAddress "$fname.$lname#contoso.mail.onmicrosoft.com"
}
Enable-MBX Jane Doe
I think you're just confused about Write-Host.
I'm not certain if you're trying to write the enable-remotemailbox to console or execute it. The code you have should work fine for writing to console (screen) but won't execute the command. To execute the command:
Enable-RemoteMailbox "$fname.$lname#contoso.com" -RemoteRoutingAddress "$fname.$lname#contosoinc.mail.onmicrosoft.com"
Anything inside of double-quotes will expand. Ex: "$fname" will expand to "Bob" if $fname is equal to "Bob". If you encapsulate the whole command in quotes in a variable though, the Write-Host will NOT execute the command. Write-Host is designed to write output to the screen so you'll just see the command in the console.
If you want to further expand, you can use the sub-string operator $(). Ex:
Write-Host "$($fname.length).$($lname.length)"
Comes back as "3.5" for "Bob" and "Smith".
To avoid expansion, use single quotes:
Write-Host '$($fname.length).$($lname.length)'
Writes "$($fname.length).$($lname.length)" to the console.
The following (similar to your code) without quotes: Write-Host $fname.$lname#contoso.com will try to pull the $lname#contoso.com Property of $fname which in this context doesn't make sense (doesn't exist). To elaborate, it would be equivalent to Write-Host $fname.($lname#contoso.com).
I have a ps1 script like below, it filters files and outputs a formatted HTML file.
$a = "<style>"
$a = $a + "BODY{background-color:peachpuff;}"
$a = $a + "TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}"
$a = $a + "TH{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:thistle}"
$a = $a + "TD{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:PaleGoldenrod}"
$a = $a + "</style>"
$b = Get-Date -Format u
Get-ChildItem -Recurse K:\AppData\*.* -Filter *.CATPart | Where{$_.LastWriteTime -gt (Get-Date).AddDays(-6)} | sort LastWriteTime -descending | select name,LastWriteTime,Directory | convertto-html -head $a -body "<H2>CATIA PAST 7 DAYS -- $b </H2>" | out-file C:\aaa\catia_result.htm
I can run this script manually with no problem at all. but when I schedule it to run, it only gives me the formatted htm file without any filtered data in there. This is arguments I used in task scheduler:
powershell.exe -ExecutionPolicy Bypass -Command "C:\aaa\RLTP_HTML_FINAL.ps1"
I tried change executionpolicy to Unrestricted, it still wont work. The task history shows the task completed, but there is no data in the HTML file.
I also tried to use a batch file call up powershell to run the script, it is the same result that it only works with manual operation but task scheduler.
Most likely, when you schedule the script to execute, it may not have a mapping to the K:\ drive. Make sure that:
The K drive is mapped in the script, using the Get-PSDrive cmdlet
Your credentials that the scheduled task is set to use have access to the K:\ drive
Alternatively, you could simply specify a UNC path, instead of referencing the K:\ drive.
ps. Good job using -ExecutionPolicy Bypass. That helps to avoid any issues with the execution policy! :) It doesn't matter what the execution policy is set to, as long as you use that parameter.
If you want to capture any errors in your script, make this your last line:
Add-Content -Path $PSScriptRoot\error.log -Value $error;
You might see something about the K:\ drive missing.