How use write to stdout without a newline? - powershell

When using the Write-Output command, a new line is automatically appended. How can I write strings to stdout (the standard output) without a newline?
For example:
powershell -command "write-output A; write-output B"
Outputs:
A
B
(Write-Host is no good - it writes data to the console itself, not to the stdout stream)

Write-Output writes objects down the pipeline, not text as in *nix for example. It doesn't do any kind of text formatting such as appending newlines, hence no need for newline handling options. I see people very often not coming to grips with this.
If you are referring to the newlines printed on the console output, it's because the pipeline is always eventually terminated by Out-Default, which forwards to a default output target (usually Out-Host), which in turn, if it doesn't receive a formatted input, runs the objects through an appropriate default formatter (usually Format-List or Format-Table). The formatter here is the only one in the process responsible for formatting the output, e.g. printing each object on a new line for the console output.
You can override this default behavior by specifying the formatter of your liking at the end of the pipeline, including your own using Format-Custom.

Write-Output is not appending the newlines.
Try this:
filter intchar {[int[]][char[]]$_}
'123' | Write-Output | intchar
49
50
51
The filter is converting the string to the ASCII int representation of each character. There is no newline being appended.
Adding a couple of explicit newlines for comparison:
"1`n2`n3" | write-output | intchar
49
10
50
10
51
Now we see the additional newlines between the characters, but still no newline appended to the string.
Not sure what your application is, but if you're getting unwanted newlines in your output, I don't think it's Write-Output that's doing it.

mjolinor/famousgarkin explain why the output has a new line that is not itself generated by Write-Output. Simple approach to deal with this is to build your output string with Write-Output
$text = ("This","is","some","words") -join " ";
$string = Write-Output $text
$string += Write-Output $text
$string
Output
This is some wordsThis is some words

Related

Usage of Write-Output is very unreliable compared to Write-Host

I was pointed at a question that suggests using Write-Output over Write-Host if I want commands to operate sequentially (as Write-Host doesn't put the output on the pipeline while other commands do, which means that Write-Host output can happen before or after other commands that are on the pipeline leading to very messy output): command execution ordering inside a PowerShell scriptblock
Following this advice, I made a simple function using Write-Output to mimic Write-Host's colour syntax. For ordering, this works well, so that output from commands is now sequential, but the colour output is now awful with Write-Output so that if I use any BackgroundColor at all, the results are sprayed over the screen in very ugly ways. Write-Host was tight and reliable with colour output and didn't bleed into other parts of the console so using Write-Output with colour makes for some really ugly/clunky console output.
Do I need to reset $host.ui in some way before leaving the function, or can anyone suggest a way to modify this function so that the colours remain tight to the areas that they are required for and don't bleed to other console areas?
function Write-Color ($text, $ForegroundColor, $BackgroundColor) {
$defaultFore = $host.ui.RawUI.ForegroundColor
$defaultBack = $host.ui.RawUI.BackgroundColor
if ($ForegroundColor -ne $null) { $host.ui.RawUI.ForegroundColor = $ForegroundColor }
if ($BackgroundColor -ne $null) { $host.ui.RawUI.BackgroundColor = $BackgroundColor }
Write-Output $text
$host.ui.RawUI.ForegroundColor = $defaultFore
$host.ui.RawUI.BackgroundColor = $defaultBack
}
e.g.
Write-Color "The dog sat on the couch" -ForegroundColor Red -BackgroundColor White
Write-Host is the right tool for producing (possibly colored) for-display output - as opposed to outputting data via PowerShell's success output stream, via cmdlet calls and expressions, (optionally via explicit Write-Output calls, but that's rarely needed).
This answer explains that if you mix Write-Host and success-stream output, in PowerShell v5+ what prints to the console can appear out of order.
This is a side effect of implicitly applied tabular formatting situationally being asynchronous, in an effort to collect some data before printing output so as to determine suitable column width. It happens only for output types that (a) don't have predefined format data, and (b) have 4 or fewer properties (because types with more properties default to list formatting).
The problematic behavior is discussed in GitHub issue #4594; while there's still hope for a solution, there has been no activity in a long time.
There is no good solution to this problem as of PowerShell 7.0:
There are two - suboptimal - workarounds:
(a) Pipe individual commands that trigger the asynchronous behavior to ... | Out-Host.
E.g., in the following command the command with the Select-Object call must be sent to Out-Host so as to appear correctly between the two Write-Host calls on the screen:
Write-Host '------- 1'
Get-Item . | Select-Object FullName | Out-Host
Write-Host '------- 2'
Downside: Using Out-Host means you lose the ability to capture or redirect the command's output, because it is sent directly to the host (display). Additionally, it is cumbersome to (a) know what commands trigger the problem and (b) to remember to apply the workaround to each.
(b) Replace Write-Host calls with sending strings with embedded VT (Virtual Terminal) escape sequences (for coloring) to the success output stream.
Note: Requires Windows PowerShell v5.1 on Windows 10 or PowerShell [Core] v6+
Downside: The (colored) strings become part of the code's data output and are therefore included when you capture / redirect output.
# Windows PowerShell 5.1: [char] 0x1b produces an ESC char.
$green = [char] 0x1b + '[32m'; $reset = [char] 0x1b + '[m'
# Print "green" in green.
"It ain't easy being ${green}green${reset}."
# PowerShell 6+: `e can be used inside "..." for ESC.
$yellow = "`e[33m"; $reset = "`e[m"
# Print "yellow" in yellow.
"They call me mellow ${yellow}yellow${reset}."
The fact that these strings contain ESC chars. could actually be used to filter out for-display strings from the data stream (assuming your actual data doesn't contain ESC chars.), along the lines of ... | Where-Object { -not ($_ -is [string] -and $_ -match '\e') }
Embedding VT escape sequences allows you to selectively color parts of your strings.
Achieving the same effect with Write-Host would require multiple calls with -NoNewline.
Third-party cmdlet (module) Write-ColoredOutput emulates Write-Host's syntax and uses the [console] type's attributes to turn coloring on and off, while sending the string to the success output stream.
This works well for writing an entire string in a given color, but you cannot piece together differently colored parts on a single line, because each string individually written to the success output stream invariably prints on its own line.
If you wanted a convenience wrapper around embedding VT sequences directly in strings, you could adapt the Write-HostColored function from this answer, by replacing the Write-Host calls that happen behind the scenes with VT sequences.

Can I use Powershell to automatically extract an unknown string with a specific pattern from a XML file and write that string in a text file?

In a XML file with 100 lines of code, there is one string with a specific pattern that I want to find and write into a new text file.
What the string contains is unknown and can vary, but the pattern is the same. For example:
12hi34
99ok45
Those have in common that the length is 6 and element:
0-1: integers
2-3: characters
4-5: integers
Is there a way to use Powershell and write a script that can find the string that fit the pattern and export it in a text file?
I'm new to Powershell and scripting. Tried to Google the problem and stumbled upon Select-String, but that doesn't solve my problem. Hope some of you can guide me here. Thanks.
Edit: The string is outside the root element as some "free text". It is not a traditional XML file.
Assuming there's only one token of interest in the file, and that the letters are limited to English letters 'a' through 'z':
(Get-Content -Raw in.xml) -replace '(?s).*(\d{2}[a-z]{2}\d{2}).*', '$1' > out.txt
Note:
If no matching token is found, the input file's entire content is written to out.txt.
On Windows PowerShell > produces UTF-16LE ("Unicode") files by default (in PowerShell Core it is UTF-8 without a BOM); pipe to Set-Content out.txt -Encoding ... instead to create a file with a different encoding.
Get-Content -Raw reads the entire input file as a single string.
The -replace operator uses regular expressions (regexes) for matching - see this answer for more information.
Inline option (?s) at the start of regex makes . match newlines too.
By default, matching is case-insensitive; use -creplace for case-sensitive matching.
Try this...
$f = Get-Content '<xml-file>' -ReadCount 0
foreach ($l in $f) {
if ($l -match '[0-9]{1,3}[a-zA-Z]{2,3}[0-9]{1,5}') {
Write-Output $matches.0
}
}
Stuffing the contents of a file into a variable. Iterating over each line of the file. Parsing out the value by pattern.
Here is a sample of the matching piece...

How to skip text from file txt when using curl command in powershell

I am using Curl command to check connection of host but in a list i have text like that. So i want to use Curl command to read this list and skip texts such as TEXT1 TEXT2 TEXT3 but still show them into screen.
Everyone, please help me how to skip it. Thank you for your helping!
TEXT1
10.0.254.161:9080
TEXT2
10.0.140.11:8866
TEXT3
10.0.110.96
There are several ways to do this.
First if you wish to show and pass through some items you can first write each item to verbose, host, information streams, and then at the end filter for the things you wish "to keep" or pass through to the next command.
Writing to verbose frequently makes a lot of sense as you can turn it off and own with your own preferences: $VerbosePreference defaults to: SilentlyContinue
Try this for a start but please understand this is not a very "PowerShell" way to do things, just an answer to your actual question:
For purposes of testing I loaded your sample data into the variable "$curl". You can just pipe the output of your actual "curl" command to the ForEach-Object at the start if you prefer:
$curl -split '\n' | # I have single string so split
ForEach-Object -begin {
$buffer=#() # initialize empty array
} -process {
write-host $_ -fore blue -back white # show all blue on white
$buffer += $_ # add each item to buffer
} -end {
$buffer # hold buffer until end
} | Where-Object { $_ -match '[\d.:]{7,}' } # filter for just IP:Port
You'll get an obvious (Blue on White) printing of everything, but at the end you'll get just the IP:Port patterns to the standard output, which you can capture to a variable, send to a file, or pipe to another command.
This match is looking for at least 7 Digits, DOTs, or COLONs, (4.4.4.4 would be about a minimal IP), but it isn't very sophisticated and would get fooled by phone numbers (without dashes or spaces):
$_ -match '[\d.:]{7,}' # any 7 digits, periods or colons will match
You can work a lot harder to match an "IP with optional Port number" if you wish, something like:
$_ -match '(\d{1,3}\.){3}(\d{1,3})(:(\d{1,5}))?' # picky match
...but it returns the same (35) items for your sample data.
1to3 digits and a dot, 3 times, then 1to3 digits, optionally followed by a COLON and 1 to 5 digits.
You could wrap it in ^ beginning of line and $ end of line if you wanted to be really stringent.
The above is really ugly for PowerShell but represent a 'minimalist' answer to the question.

UTF8 Encoding changes data Format

I'm trying to get the output of a command in PowerShell and encode it and then decode it again to receive the results of the said command as shown.
$enc = [system.Text.Encoding]::UTF8
$bytes = $enc.GetBytes((Invoke-Expression "net users"))
$enc.GetString($bytes)
However, the result comes out malformed as opposed to the original net users command. I've tried changing the encodings to ASCII and Unicode and still the result is malformed.
Any ideas on how to maintain the formatting?
The problem isn't caused by the encoding, but because PowerShell will mangle the command output unless you force it into a string:
$bytes = $enc.GetBytes((Invoke-Expression "net users" | Out-String))
You don't need Invoke-Expression BTW. This will work as well:
$bytes = $enc.GetBytes((net users | Out-String))
To complement Ansgar Wiechers' helpful answer:
Invoking an external command returns the output lines as an array of strings.
Because Encoding.GetBytes() expects a single string as input, the array was implicitly coerced to a single string, in which case PowerShell joins the array elements using the space character, so the original line formatting was lost; e.g.:
PS> [string] 1, 2, 3
1 2 3 # single string containing the array elements joined with spaces
Piping to Out-String, as in Ansgar's answer, prevents creation of the array and returns the external command output as a single string.
PS> (1, 2, 3 | Out-String | Measure-Object).Count
1 # Out-String output a single string
Another option would be to join the array elements with newlines on demand (you won't see the difference in the console, but you do get a single, multi-line output string with this technique):
PS> (net users) -join "`n" # or, more robustly: [environment]::NewLine
Note: With this technique, the output string will not have a trailing newline, unlike when you use Out-String.
Out-String always appends a trailing newline, which can be undesired.
Alternatively, you can tell PowerShell what encoding to expect from an external command by setting [Console]::OutputEncoding (temporarily):
However, that is only necessary if you know the external utility to use an output encoding other than the default (your system's active OEM code page) - and I doubt that that's necessary for net users; that said, here's how it would work:
$prevEnc = [Console]::OutputEncoding
[Console]::OutputEncoding = New-Object System.Text.UTF8Encoding
$str = net users | Out-String # `net users` output is now properly decoded as UTF-8
[Console]::OutputEncoding = $prevEnc

How can I replace newlines using PowerShell?

Given test.txt containing:
test
message
I want to end up with:
testing
a message
I think the following should work, but it doesn't:
Get-Content test.txt |% {$_-replace "t`r`n", "ting`r`na "}
How can I do a find and replace where what I'm finding contains CRLF?
A CRLF is two characters, of course, the CR and the LF. However, `n consists of both. For example:
PS C:\> $x = "Hello
>> World"
PS C:\> $x
Hello
World
PS C:\> $x.contains("`n")
True
PS C:\> $x.contains("`r")
False
PS C:\> $x.replace("o`nW","o There`nThe W")
Hello There
The World
PS C:\>
I think you're running into problems with the `r. I was able to remove the `r from your example, use only `n, and it worked. Of course, I don't know exactly how you generated the original string so I don't know what's in there.
In my understanding, Get-Content eliminates ALL newlines/carriage returns when it rolls your text file through the pipeline. To do multiline regexes, you have to re-combine your string array into one giant string. I do something like:
$text = [string]::Join("`n", (Get-Content test.txt))
[regex]::Replace($text, "t`n", "ting`na ", "Singleline")
Clarification: small files only folks! Please don't try this on your 40 GB log file :)
With -Raw you should get what you expect
If you want to remove all new line characters and replace them with some character (say comma) then you can use the following.
(Get-Content test.txt) -join ","
This works because Get-Content returns array of lines. You can see it as tokenize function available in many languages.
You can use "\\r\\n" also for the new line in powershell. I have used this in servicenow tool.
In my case "\r\n" s not working so i tried "\\r\\n" as "\" this symbol work as escape character in powershell.
You can detect if a file is CRLF with this simple Powershell instruction
(cat -Raw $args) -match "\r\n$"
Replacing \n with \r\n is tricky because you have to detect it first and apply the replacement only if it is needed, otherwise it would be a mess. Too complex.
In any case, you can forget detection, to ensure a file is CRLF whatever the original type you can do this in PowerShell:
cat $file > $file