variables in write-host command

I want the following command executed. which should be 6 spaces with a red background with no newline

write-host " "*6 -backgroundcolor red -nonewline

I am trying to accomplish this with variables, but am missing something

$newline = " -nonewline"
$color = " -backgroundcolor red" 
$count = " "*6

write-host $count $color $newline

I need to be able to use variables to control the color and -nonewline switch. My example of how I am trying to do it is faulty. How could I accomplish this?

I think I found a good solution: invoke-expression

invoke-expression "write-host $count $color $newline"

You were almost there. Have a look at splatting. You can create a hash table with the names of the parameters and the values you wish to supply to those parameters then pass the hash table variable to the cmdlet prefixed with an @ symbol. Eg.

$hash=@{object="test";foregroundcolor="red"}
Write-host @hash

other acceptable variant

$nonewline = $true
$color = ‘red’
$count = " "*6
write-host $count -backgroundcolor $color -nonewline:$nonewline

invoke-expression is a BAD variant. It’s contr-intuitive and vulnerable to exploits and nasty bugs that difficult to detect

$foo=13
write-host $(" "*$foo) -BackgroundColor red -NoNewline

I finished my introduction to my first program, a tic tac toe game. What do you think.

https://gist.github.com/shanenin/f164c483db513b88ce91

Optimized code style (with comments, why that way is better )

#this function converts a value to pixels to create billy
function write-billy{
    
    #these are the pixels(spaces) that make up the ascii image
    $billy = ('sb8','nl9','sb6','sl4','sw5','nl4','sb5','sl3','sw9',
    'nl3', 'sb4','sl3','sw11','nl3','sb3','sl3','sw3','sr3','sw1',
    'sr3','sw3','nl3','sb3','sl3','sw2','sl1','sr1','sl1','sr1','sw1',
    'sr1','sl1','sr1','sl1','sw2','nl4','sb2','sl3','sw4','sr3','sw1',
    'sr3','sw4','nl3','sb2','sl3','sw1','sr1','sw1','sr1','sw7','sr1',
    'sw1','sr1','sw1','nl3','sb1','sl5','sw1','sr1','sw9','sr1','sw1',
    'nl5','sb1','sl7','sw1','sr7','sw1','nl7','sb2','sl6','sw2','sl1',
    'sw3','sl1','sw2','nl6','sb3','sl4','sr2','sw1','sl1','sw3','sl1',
    'sw1','sr2','nl4','sb7','sl1','sr9','nl1','sb5','sl2','sr2','sl2',
    'sw3','sl2','sr2','nl2','sb3','sl9','nl9','sb2','nl21','sb1','nl23')

    foreach ($i in $billy){
        
       #this part determines how many spaces to print
       # if you need string from some character to end
       # you can use another substring() overload
       $manychars = $i.substring(2)
       
        #this next part determines the color to print
        # switch statement in this case more intuitive and readable
        # you can user [] indexer if you need string characters one by one
        switch ($i[1]) {
            'r' { $color = 'red' }
            'l' { $color = 'black' }
            'w' { $color = 'white' }
            default { $color = $host.UI.RawUI.BackgroundColor } # default console color
        }
        
        #this part determines if it needs a -nonewline added
        $newline = ($i[0] -eq 's') # already boolean(true/false) type
        # right variable usage in this case ( Invoke-Expression > $null )
        Write-Host (' '*$manychars) -BackgroundColor $color -NoNewLine:$newline

    }
}

function write-slow ($text, $delay){
     # Do not need string splitting, you can use string as char array
     foreach ($i in $text.ToCharArray()){
         # do not need any intermediate variables
         Write-Host -NoNewline $i
         Start-Sleep -Milliseconds $delay
     }
     Write-Host
}


write-billy
Write-Host
write-slow 'Would you like to play a game?' 125
Write-Host
write-slow 'press enter to fulfill your destiny' 125
Read-Host

Thanks Max. Those were some great suggestions :slight_smile:

forget to say, i change write slow style to one-by-one character output, and youth - word by word
your variant without extra variables:
function write-slow ($text, $delay){
foreach ($i in $text.split(" ")){
Write-Host -NoNewline ($i + " ")
Start-Sleep -Milliseconds $delay
}
write-host
}

another variant with -byword output, but it out space symbol as word (and implement delay on it, thus you need two times shorter delay to the same speed). this time use powershell native split operator with regular expression

function write-slow ($text, $delay){
foreach ($i in ($text -split ‘(\s)’)){
Write-Host -NoNewline $i
Start-Sleep -Milliseconds $delay
}
write-host
}

third variant :slight_smile:

function write-slow ($text, $delay){
# Do not need string splitting, you can use string as char array
foreach ($i in $text.ToCharArray()){
# do not need any intermediate variables
Write-Host -NoNewline $i
if ($i -eq ’ ') {
Start-Sleep -Milliseconds $delay
}
}
Write-Host
}

I like the code, but when I am trying it, I am not able to use the envirmental variable for background color

PS C:\Users\shane> Write-Host gggggggggg -BackgroundColor $host.UI.RawUI.BackgroundColor
Write-Host : Cannot process the color because -1 is not a valid color.
Parameter name: value
Actual value was -1.
At line:1 char:1
+ Write-Host gggggggggg -BackgroundColor $host.UI.RawUI.BackgroundColor
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Write-Host], ArgumentOutOfRangeException
    + FullyQualifiedErrorId : SetInvalidBackgroundColor,Microsoft.PowerShell.Commands.WriteHostCommand

This is because you use ISE,
in pure Powershell: PS D:> $host.UI.RawUI.BackgroundColor
DarkMagenta

in ISE: PS D:> $host.UI.RawUI.BackgroundColor
-1

You can use this workaround
somewhere in the beginning of your script:
$defaultColor = $host.UI.RawUI.BackgroundColor
if ($defaultColor -eq -1) { $defaultColor = ‘DarkMagenta’ } #or some another color you need

and in switch()
default { $color = $defaultColor }

Thanks :slight_smile: