Skip to content

Instantly share code, notes, and snippets.

@dlenski
Last active March 10, 2026 00:15
Show Gist options
  • Select an option

  • Save dlenski/fb38419ca862bb6d2f718726113eb29e to your computer and use it in GitHub Desktop.

Select an option

Save dlenski/fb38419ca862bb6d2f718726113eb29e to your computer and use it in GitHub Desktop.
Quote Python strings as safe string literals for PowerShell
#!/usr/bin/env python3
r'''Quote Python strings in such a way that they can be used safely as string
literals in a Windows PowerShell script.
The approach suggested in https://stackoverflow.com/a/1056978 seems to be the
least-insane way to safely quote non-ASCII characters, along with
https://stackoverflow.com/a/60825495 as a useful refinement for PowerShell
v6.0+, where a slightly less verbose syntax for unicode escapes is possible.
PowerShell string literal syntax is different from basically every other
modern programming language, and not particularly well-documented.
A particularly crazy mis-feature is that "smart quote" characters (non-ASCII quotation
characters!) are treated as equivalent to normal ASCII quotation characters, and thus
must be escaped. 😵‍💫
See https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_quoting_rules
and https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_special_characters
for some official documentation in Microsoft's very non-linear style.
'''
import re
# Characters that need quoting/escaping in double-quoted strings
# in PowerShell:
#
# ' ' (32): safe
# '!' (33): safe
# '"' (34): needs doubling or `-escaping
# '#' (35): safe
# '$' (36): needs `-escaping
# '%'-'_' (37-95): safe
# '`' (96): needs doubling or `-escaping
# 'a'-'~' (97-126): safe
# '\n\r\t\0\a\b\f\v': use ` instead of \
# Rest of UTF-8 BMP: "$([char]codepoint)"
# Rest of UTF-8: "$([char]::ConvertFromUtf32(codepoint))"
#
# PowerShell 6+ only:
# '\x1b': use `e
# Rest of UTF-8: `u{hex codepoint}
_NEED_PS_QUOTE = re.compile(r'[^ !#%-_a-~]')
def _ps_quote_compat(m):
c = m.group(0)
if c in '"$`':
return f'`{c}'
elif (o := '\n\r\t\0\a\b\f\v'.find(c)) >= 0: # \e only exists in PowerShell 6+
return f'`{"nrt0abfv"[o]}'
elif (o := ord(c)) <= 0xffff:
return f'$([char]{o})'
else:
return f'$([char]::ConvertFromUtf32({o}))'
def _ps_quote_v6(m):
c = m.group(0)
if c in '"$`':
return f'`{c}'
elif (o := '\n\r\t\0\a\b\f\v\x1b'.find(c)) >= 0:
return f'`{"nrt0abfve"[o]}'
else:
return '`u{%X}' % ord(c)
def psquote(s: str, v6: bool = False):
'''Quote and escape a Python string in such a way that it can be
used safely as a string literal in a Windows PowerShell script.
All non-ASCII characters will be escaped, as well as characters
that are parsed specially by PowerShell.
Using v6 gives a slightly more concise output for non-ASCII
characters, but is only compatible with PowerShell v6.0+
'''
return '"' + _NEED_PS_QUOTE.sub(_ps_quote_v6 if v6 else _ps_quote_compat, s) + '"'
if __name__ == '__main__':
assert psquote('foo$(\u03BC)bar\n\U0001F973`', v6=False) == '"foo`$($([char]956))bar`n$([char]::ConvertFromUtf32(129395))``"'
assert psquote('foo$(\u03BC)bar\n\U0001F973`', v6=True) == '"foo`$(`u{3BC})bar`n`u{1F973}``"'
print("All tests passed \U0001F973")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment