Search code examples
powershellcontrol-characters

error defining array in a script, it works if typed out however


I'm trying to create an audio toggle. I've written it before but new OS and dll updates forced me to rewrite it, the method i used previously doesn't seem to work any longer. So right out of the gate my first line spits out this error:

$audio : The term '$audio' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that 
the path is correct and try again.
At D:\audiochanger.ps1:1 char:1
+ $audio = Get-AudioDevice -playback
+ ~~~~~~~
    + CategoryInfo          : ObjectNotFound: ($audio:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

but if i type in $audio = Get-AudioDevice -playback and then call $audio, it works perfectly fine. Whats going on?

$audio = Get-AudioDevice -playback
$audio.Name
if ($audio.Name -eq 'Speakers (Realtek High Definition Audio)') {
set-audiodevice 1 
}  Else {
set-audiodevice 2
}

output of Get-AudioDevice -playback


Index   : 2
Default : True
Type    : Playback
Name    : Speakers (Realtek High Definition Audio)
ID      : {0.0.0.00000000}.{2aa2a27b-4ebc-4355-bdf7-093a8f97ba46}
Device  : CoreAudioApi.MMDevice

or

Index   : 1
Default : True
Type    : Playback
Name    : Speakers (Logitech G533 Gaming Headset)
ID      : {0.0.0.00000000}.{1f5d6b65-fe9b-4bda-9508-d1a204149395}
Device  : CoreAudioApi.MMDevice

this is running on windows 10 and powershell 5. my previous working code can be found here: need to select an item based on the name in an array using powershell


Solution

  • The only plausible explanation is that you have invisible control characters before $audio in your script file.

    If your line truly started with $audio = ... it would be interpreted as an assignment, as intended; instead, what looks like $audio is being interpreted as the name of a command, which implies that $ is not actually the 1st character.

    You can reproduce the problem as follows:

    [char] 0x200b + '$audio = Get-AudioDevice -playback' > t.ps1
    ./t.ps1
    

    The above yields the error you saw, due to invisible control character U+200B(ZERO WIDTH SPACE)) preceding $audio.

    While this particular control character is just an example, you can inspect the actual characters on your script's first line as follows:

     & { 
       [int[]] [char[]] $Args[0] | % { '0x{0:x} [{1}]' -f $_, [char] $_ } 
     } (get-content D:\audiochanger.ps1)[0]
    

    The solution is to remove the invisible character(s); the following may work, depending on what characters are actually present in your case:

     (Get-Content D:\audiochanger.ps1) -replace '\p{Cf}' > D:\audiochanger.CleanedUp.ps1
    

    Regex \p{Cf} matches all instances of invisible control characters .