Home > Enterprise >  FindWindow in Powershell gives me 0 (on w11 22h2 FR) : unattended character in the title of a cmd el
FindWindow in Powershell gives me 0 (on w11 22h2 FR) : unattended character in the title of a cmd el

Time:12-15

8 years after this question with Windows 11 22H2 FR, in Powershell PSVersion 5.1.22621.169 the command:

FindWindow("ConsoleWindowClass", "Administrateur : X:\windows\system32\cmd.exe")

outputs 0.

After some rechearch, I use SPY for reading caption and class. I have copy/pasted from the editbox of SpY into a PS string variable ($title). And I notice in this copy/pasted $title string:

[byte]$title[14]= 160

[byte]$title[14] looks like a space and is here, in the middle "r :" String index 14 is for french version of OS.

FindWindow returns a good handle with this character!

Question : Why [byte]$title[14] = 160 (at index 14 in the string for FR) is found in the title of an elevated cmd console? Is it normal? Where is it documented?

The code I used:

$code = @'
[DllImport("user32.dll", CharSet=CharSet.Unicode, SetLastError = true)]
public static extern IntPtr FindWindow(string ClassName,string WindowName);
[DllImport("user32.dll", CharSet=CharSet.Unicode, SetLastError = true)]
public static extern bool ShowWindow( IntPtr hWnd, int  nCmdShow);
[DllImport("user32.dll", CharSet=CharSet.Unicode, SetLastError = true)]
public static extern IntPtr SetWindowText(IntPtr HWND, string Text);
'@
Add-Type  -MemberDefinition $code -Name Window -Namespace Test
# please, open an elevated console cmd
#Be carrefull, "administrateur" in french OS. So, adapt if you test...
# here,  "[byte]$title[14] = 32" -> it's a space, it's not 160
$name = "Administrateur : X:\windows\system32\cmd.exe"
$classW = "ConsoleWindowClass"
[Test.Window]::FindWindow($classW, $name)
#it gives 0

I don't know how to put a code point of 160 into a system.string (I can only copy/paste the title from SPY ). So I can't give the correct code for the second test.

In summary:

I launch a cmd console elevated and see the title:

"Administrateur : X:\windows\system32\cmd.exe"
...............|..............................

The above line is for locating the position of the "strange" character with code point of 160.

With PS, i try to use FindWindow to get a handle on this window If I copy/paste the title from SPY ([byte]$title[14] = 160), FindWindow is OK.

If I enter the text from the keyboard ([byte]$title[14] = 32), FindWindow returns 0 (error).

Is it normal to get a title text with code point 160 (at index 14 in the string for FR)?

CodePudding user response:

The Unicode character whose code point is 160 (decimal) / 0xA0 (hexadecimal) is:

It looks just like a space, but is obviously different from it.

To embed in a string, you have several options; the easiest is to use an expandable (double-quoted) string ("...") with either an embedded subexpression ($(...) or, in PowerShell (Core) 6 only, a Unicode escape sequence:

# Subexpression:
# Works in Windows PowerShell too.
"Administrateur$([char] 0xA0): X:\windows\system32\cmd.exe"

# Unicode escape sequence: 
# Works in PowerShell (Core) 6  only
"Administrateur`u{A0}: X:\windows\system32\cmd.exe"

As for why this character is present:

The original purpose of the character is to prevent automatic line breaks between words, which a regular space character wouldn't do - see Wikipedia's article on the non-breaking space.

Given that window titles are always single-line, that alone cannot be the reason for the character's use.

With English or German as the system language, for instance, the character is not present: there's simply no character between the (localized) word for administrator and :

zett42 observes the following with respect to why the character is present in French, for instance:

  • In French (and possibly other languages), : (and other punctuation) must be preceded by a (non-breaking) space - see What’s The Deal With French Spacing?

  • In general, it makes sense to use a no-break space between : and the word that precedes it, so as not have a "dangling" : on a new line.

  • Possibly, there is shared code that inserts the no-break space before : for text localized to French, so that it just happens to surface in this context too.

Pragmatically speaking:

  • The behavior is obscure with respect to finding windows running elevated sessions by title.

  • With respect to parsing such a title (once found), splitting into the part before and after the : actually then works the same in all languages, but only if you split by regular spaces only, such as with
    "Administrateur$([char] 0xA0): X:\windows\system32\cmd.exe" -split ' ' (by contrast, -split "Administrateur$([char] 0xA0): X:\windows\system32\cmd.exe" would split by the no-break space too).


As for how to diagnose the problem programmatically:

(Get-Process -Name cmd | Where-Object MainWindowTitle -Match '^Administr').MainWindowTitle | 
  ForEach-Object ToCharArray |
  ForEach-Object {
    [pscustomobject] @{ Char = $_; CodePoint = '0x{0:x}' -f ([uint16] $_) }
  }

The above prints each character alongside its Unicode code point on its own line.

This answer shows convenience function Debug-String, which greatly simplifies examining strings for unexpected characters.

  • Related