emacs.d/clones/lisp/www.cliki.net/PowerShell.html
2022-10-07 15:47:14 +02:00

182 lines
No EOL
38 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>CLiki: PowerShell</title>
<link rel="alternate" type="application/atom+xml" title="ATOM feed of edits to current article"
href="https://www.cliki.net/site/feed/article.atom?title=PowerShell">
<link rel="stylesheet" href="static/css/style.css">
<link rel="stylesheet" href="static/css/colorize.css">
</head>
<body>
<span class="hidden">CLiki - PowerShell</span>
<div id="content"><div id="content-area"><div id="article-title">PowerShell</div><div id="article">An experiment in sending tasks to <a href="https://en.wikipedia.org/wiki/PowerShell">PowerShell</a> from CL. The Perl Batcave has this thing lying around: <a href="https://metacpan.org/pod/Win32::PowerShell::IPC">Win32::PowerShell::IPC</a>. It's possible to steal this technique for Common Lisp. <a href="CCL.html" class="internal">CCL</a> handles a lot of the tricky OS-level details (like I/O on pipes). But a PowerShell "cmdlet" normally produces an array of objects—which have "properties"—and it can be expedient to get them in the form of S-expressions (or at least lists).<p>A quick-and-dirty way to do this is to arrange for PowerShell to format the result as one big string, and then parse the output into a <a href="Lisp.html" class="category">Lisp</a> list. This is done by designating two separator characters: the "vertical tab" character as a separator between objects, and the null character to separate properties within an object. These correspond (respectively) to <tt>#\PageUp</tt> and <tt>#\Nul</tt> in CCL, or <tt>`v</tt> and <tt>`0</tt> in PowerShell. (Unlike many other languages, PowerShell uses the backtick as an escape character in double-quoted strings.)<p><h2>The code</h2><p>Licensed under <a href="Apache&#32;2.html" class="category">Apache 2</a>. The external-process management is specific to <a href="CCL.html" class="internal">Clozure CL</a>.<p><div class="code"><span class="nonparen"><span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defparametercm_defvar.html" class="symbol"><i><span class="symbol">defvar</span></i></a> <span class="special">*powershell*</span> <a href="https://www.cliki.net/site/HyperSpec/Body/any_nil.html" class="symbol">nil</a>
<span class="string">"If set: an EXTERNAL-PROCESS."</span></span>)</span>
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defun.html" class="symbol"><i><span class="symbol">defun</span></i></a> open-powershell <span class="paren2">(<span class="nonparen"></span>)</span>
<span class="string">"Start PowerShell and save it in *POWERSHELL*."</span>
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/spefor_setq.html" class="symbol"><i><span class="symbol">setq</span></i></a> <span class="special">*powershell*</span> <span class="paren3">(<span class="nonparen">run-program <span class="string">"powershell.exe"</span>
'<span class="paren4">(<span class="nonparen"><span class="string">"-Command"</span> <span class="string">"-"</span></span>)</span>
<span class="keyword">:wait</span> <a href="https://www.cliki.net/site/HyperSpec/Body/any_nil.html" class="symbol">nil</a>
<span class="keyword">:input</span> <span class="keyword">:stream</span>
<span class="keyword">:error</span> <span class="keyword">:stream</span>
<span class="keyword">:output</span> <span class="keyword">:stream</span></span>)</span></span>)</span></span>)</span>
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defun.html" class="symbol"><i><span class="symbol">defun</span></i></a> close-powershell <span class="paren2">(<span class="nonparen">&amp;optional <span class="paren3">(<span class="nonparen">powershell <span class="special">*powershell*</span></span>)</span></span>)</span>
<span class="string">"Close associated streams, causing PowerShell to exit."</span>
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_close.html" class="symbol">close</a> <span class="paren3">(<span class="nonparen">external-process-input-stream powershell</span>)</span></span>)</span>
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_close.html" class="symbol">close</a> <span class="paren3">(<span class="nonparen">external-process-error-stream powershell</span>)</span></span>)</span>
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_close.html" class="symbol">close</a> <span class="paren3">(<span class="nonparen">external-process-output-stream powershell</span>)</span></span>)</span></span>)</span>
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defun.html" class="symbol"><i><span class="symbol">defun</span></i></a> make-command-boundary <span class="paren2">(<span class="nonparen">command</span>)</span>
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_loop.html" class="symbol"><i><span class="symbol">loop</span></i></a> for boundary-code = <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_random.html" class="symbol">random</a> <a href="https://www.cliki.net/site/HyperSpec/Body/convar_most-p_ative-fixnum.html" class="symbol">most-positive-fixnum</a></span>)</span>
for boundary = <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_format.html" class="symbol">format</a> <a href="https://www.cliki.net/site/HyperSpec/Body/any_nil.html" class="symbol">nil</a> <span class="string">"END_COMMAND_~36R"</span> boundary-code</span>)</span>
while <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_search.html" class="symbol">search</a> boundary command</span>)</span> finally <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_return.html" class="symbol">return</a> boundary</span>)</span></span>)</span></span>)</span>
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_define-condition.html" class="symbol"><i><span class="symbol">define-condition</span></i></a> powershell-error <span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_error.html" class="symbol">error</a></span>)</span>
<span class="paren2">(<span class="nonparen"><span class="paren3">(<span class="nonparen">command <span class="keyword">:initarg</span> <span class="keyword">:command</span> <span class="keyword">:reader</span> powershell-error-command</span>)</span>
<span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_string.html" class="symbol">string</a> <span class="keyword">:initarg</span> <span class="keyword">:string</span> <span class="keyword">:reader</span> powershell-error-string</span>)</span></span>)</span>
<span class="paren2">(<span class="nonparen"><span class="keyword">:report</span> <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_lambda.html" class="symbol"><i><span class="symbol">lambda</span></i></a> <span class="paren4">(<span class="nonparen">powershell-error reporting-stream</span>)</span>
<span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_format.html" class="symbol">format</a> reporting-stream
<span class="string">"PowerShell error on command ~S:~%~A"</span>
<span class="paren5">(<span class="nonparen">powershell-error-command powershell-error</span>)</span>
<span class="paren5">(<span class="nonparen">powershell-error-string powershell-error</span>)</span></span>)</span></span>)</span></span>)</span></span>)</span>
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defun.html" class="symbol"><i><span class="symbol">defun</span></i></a> run-powershell <span class="paren2">(<span class="nonparen">command &amp;optional <span class="paren3">(<span class="nonparen">powershell <span class="special">*powershell*</span></span>)</span></span>)</span>
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_letcm_letst.html" class="symbol"><i><span class="symbol">let*</span></i></a> <span class="paren3">(<span class="nonparen"><span class="paren4">(<span class="nonparen">input-stream <span class="paren5">(<span class="nonparen">external-process-input-stream powershell</span>)</span></span>)</span>
<span class="paren4">(<span class="nonparen">output-stream <span class="paren5">(<span class="nonparen">external-process-output-stream powershell</span>)</span></span>)</span>
<span class="paren4">(<span class="nonparen">error-stream <span class="paren5">(<span class="nonparen">external-process-error-stream powershell</span>)</span></span>)</span>
<span class="paren4">(<span class="nonparen">boundary <span class="paren5">(<span class="nonparen">make-command-boundary command</span>)</span></span>)</span>
<span class="paren4">(<span class="nonparen">end-line <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_format.html" class="symbol">format</a> <a href="https://www.cliki.net/site/HyperSpec/Body/any_nil.html" class="symbol">nil</a> <span class="string">"echo ~A"</span> boundary</span>)</span></span>)</span></span>)</span>
<span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_write-str_m_write-line.html" class="symbol">write-line</a> command input-stream</span>)</span>
<span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_write-str_m_write-line.html" class="symbol">write-line</a> end-line input-stream</span>)</span>
<span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_finish-ou_clear-output.html" class="symbol">force-output</a> input-stream</span>)</span>
<span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_letcm_letst.html" class="symbol"><i><span class="symbol">let</span></i></a> <span class="paren4">(<span class="nonparen"><span class="paren5">(<span class="nonparen">result-string
<span class="paren6">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_with-output-to-string.html" class="symbol"><i><span class="symbol">with-output-to-string</span></i></a> <span class="paren1">(<span class="nonparen">result-stream</span>)</span>
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_loop.html" class="symbol"><i><span class="symbol">loop</span></i></a> with pending-line = <a href="https://www.cliki.net/site/HyperSpec/Body/any_nil.html" class="symbol">nil</a>
for line = <span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_read-line.html" class="symbol">read-line</a> output-stream</span>)</span> until <span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_equal.html" class="symbol">equal</a> line boundary</span>)</span>
<a href="https://www.cliki.net/site/HyperSpec/Body/mac_whencm_unless.html" class="symbol">when</a> pending-line <a href="https://www.cliki.net/site/HyperSpec/Body/mac_docm_dost.html" class="symbol">do</a> <span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_write-str_m_write-line.html" class="symbol">write-line</a> pending-line result-stream</span>)</span>
<a href="https://www.cliki.net/site/HyperSpec/Body/mac_docm_dost.html" class="symbol">do</a> <span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/spefor_setq.html" class="symbol"><i><span class="symbol">setq</span></i></a> pending-line line</span>)</span>
finally <span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_whencm_unless.html" class="symbol">when</a> pending-line
<span class="comment">;; Don't write the trailing #\Newline.
</span> <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_write-str_m_write-line.html" class="symbol">write-string</a> pending-line result-stream</span>)</span></span>)</span></span>)</span></span>)</span></span>)</span>
<span class="comment">;; We have read up to (and including) the boundary.
</span> <span class="comment">;; Now consume all available output from ERROR-STREAM.
</span> <span class="paren5">(<span class="nonparen">error-string
<span class="paren6">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_with-output-to-string.html" class="symbol"><i><span class="symbol">with-output-to-string</span></i></a> <span class="paren1">(<span class="nonparen">buffer</span>)</span>
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_loop.html" class="symbol"><i><span class="symbol">loop</span></i></a> for <a href="https://www.cliki.net/site/HyperSpec/Body/acc_charcm_schar.html" class="symbol">char</a> = <span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_read-char-no-hang.html" class="symbol">read-char-no-hang</a> error-stream</span>)</span>
while <a href="https://www.cliki.net/site/HyperSpec/Body/acc_charcm_schar.html" class="symbol">char</a> <a href="https://www.cliki.net/site/HyperSpec/Body/mac_docm_dost.html" class="symbol">do</a> <span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_write-char.html" class="symbol">write-char</a> <a href="https://www.cliki.net/site/HyperSpec/Body/acc_charcm_schar.html" class="symbol">char</a> buffer</span>)</span></span>)</span></span>)</span></span>)</span></span>)</span>
<span class="comment">;; Did we get an ERROR-STRING?
</span> <span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_if.html" class="symbol"><i><span class="symbol">if</span></i></a> <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_minuspcm_plusp.html" class="symbol">plusp</a> <span class="paren6">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_length.html" class="symbol">length</a> error-string</span>)</span></span>)</span>
<span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_error.html" class="symbol">error</a> 'powershell-error
<span class="keyword">:command</span> command
<span class="keyword">:string</span> error-string</span>)</span>
result-string</span>)</span></span>)</span></span>)</span></span>)</span>
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defun.html" class="symbol"><i><span class="symbol">defun</span></i></a> parse-powershell-output <span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_string.html" class="symbol">string</a></span>)</span>
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_whencm_unless.html" class="symbol">when</a> <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_equal.html" class="symbol">equal</a> <a href="https://www.cliki.net/site/HyperSpec/Body/any_string.html" class="symbol">string</a> <span class="string">""</span></span>)</span> <span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_return-from.html" class="symbol"><i><span class="symbol">return-from</span></i></a> parse-powershell-output <a href="https://www.cliki.net/site/HyperSpec/Body/any_nil.html" class="symbol">nil</a></span>)</span></span>)</span>
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_letcm_letst.html" class="symbol"><i><span class="symbol">let</span></i></a> <span class="paren3">(<span class="nonparen"><span class="paren4">(<span class="nonparen">end <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_length.html" class="symbol">length</a> <a href="https://www.cliki.net/site/HyperSpec/Body/any_string.html" class="symbol">string</a></span>)</span></span>)</span> <span class="paren4">(<span class="nonparen">pending-property <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_make-stri_utput-stream.html" class="symbol">make-string-output-stream</a></span>)</span></span>)</span></span>)</span>
<span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_fletcm_scm_macrolet.html" class="symbol"><i><span class="symbol">macrolet</span></i></a> <span class="paren4">(<span class="nonparen"><span class="paren5">(<span class="nonparen">get-property <span class="paren6">(<span class="nonparen"></span>)</span> `<span class="paren6">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_get-outpu_tream-string.html" class="symbol">get-output-stream-string</a> pending-property</span>)</span></span>)</span></span>)</span>
<span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_loop.html" class="symbol"><i><span class="symbol">loop</span></i></a> with <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_list.html" class="symbol">list</a> sublist</span>)</span> = <a href="https://www.cliki.net/site/HyperSpec/Body/any_nil.html" class="symbol">nil</a>
for i of-type <a href="https://www.cliki.net/site/HyperSpec/Body/typ_fixnum.html" class="symbol">fixnum</a> from 0 to end
for <a href="https://www.cliki.net/site/HyperSpec/Body/acc_charcm_schar.html" class="symbol">char</a> = <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_whencm_unless.html" class="symbol">when</a> <span class="paren6">(<span class="nonparen">&lt; i end</span>)</span> <span class="paren6">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/acc_charcm_schar.html" class="symbol">char</a> <a href="https://www.cliki.net/site/HyperSpec/Body/any_string.html" class="symbol">string</a> i</span>)</span></span>)</span>
<a href="https://www.cliki.net/site/HyperSpec/Body/mac_docm_dost.html" class="symbol">do</a> <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_cond.html" class="symbol"><i><span class="symbol">cond</span></i></a> <span class="paren6">(<span class="nonparen"><span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_or.html" class="symbol">or</a> <span class="paren2">(<span class="nonparen">= i end</span>)</span> <span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_chareqcm__ar-not-lessp.html" class="symbol">char=</a> <a href="https://www.cliki.net/site/HyperSpec/Body/acc_charcm_schar.html" class="symbol">char</a> <span class="character">#\PageUp</span></span>)</span></span>)</span>
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_if.html" class="symbol"><i><span class="symbol">if</span></i></a> sublist
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_progn.html" class="symbol"><i><span class="symbol">progn</span></i></a>
<span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_push.html" class="symbol">push</a> <span class="paren4">(<span class="nonparen">get-property</span>)</span> sublist</span>)</span>
<span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_push.html" class="symbol">push</a> <span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_reversecm_nreverse.html" class="symbol">nreverse</a> sublist</span>)</span> <a href="https://www.cliki.net/site/HyperSpec/Body/any_list.html" class="symbol">list</a></span>)</span>
<span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/spefor_setq.html" class="symbol"><i><span class="symbol">setq</span></i></a> sublist <a href="https://www.cliki.net/site/HyperSpec/Body/any_nil.html" class="symbol">nil</a></span>)</span></span>)</span>
<span class="comment">;; One property, no sublist.
</span> <span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_push.html" class="symbol">push</a> <span class="paren3">(<span class="nonparen">get-property</span>)</span> <a href="https://www.cliki.net/site/HyperSpec/Body/any_list.html" class="symbol">list</a></span>)</span></span>)</span>
<span class="comment">;; Done parsing?
</span> <span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_whencm_unless.html" class="symbol">when</a> <span class="paren2">(<span class="nonparen">= i end</span>)</span>
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_return-from.html" class="symbol"><i><span class="symbol">return-from</span></i></a> parse-powershell-output
<span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_reversecm_nreverse.html" class="symbol">nreverse</a> <a href="https://www.cliki.net/site/HyperSpec/Body/any_list.html" class="symbol">list</a></span>)</span></span>)</span></span>)</span></span>)</span>
<span class="paren6">(<span class="nonparen"><span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_chareqcm__ar-not-lessp.html" class="symbol">char=</a> <a href="https://www.cliki.net/site/HyperSpec/Body/acc_charcm_schar.html" class="symbol">char</a> <span class="character">#\Nul</span></span>)</span>
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_push.html" class="symbol">push</a> <span class="paren2">(<span class="nonparen">get-property</span>)</span> sublist</span>)</span></span>)</span>
<span class="paren6">(<span class="nonparen"><span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_write-char.html" class="symbol">write-char</a> <a href="https://www.cliki.net/site/HyperSpec/Body/acc_charcm_schar.html" class="symbol">char</a> pending-property</span>)</span></span>)</span></span>)</span></span>)</span></span>)</span></span>)</span></span>)</span>
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defun.html" class="symbol"><i><span class="symbol">defun</span></i></a> run-powershell* <span class="paren2">(<span class="nonparen">command &amp;optional <span class="paren3">(<span class="nonparen">powershell <span class="special">*powershell*</span></span>)</span></span>)</span>
<span class="paren2">(<span class="nonparen">parse-powershell-output <span class="paren3">(<span class="nonparen">run-powershell command powershell</span>)</span></span>)</span></span>)</span>
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defmacro.html" class="symbol"><i><span class="symbol">defmacro</span></i></a> $ <span class="paren2">(<span class="nonparen">control-string &amp;rest format-arguments</span>)</span>
<span class="paren2">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/speope_letcm_letst.html" class="symbol"><i><span class="symbol">let</span></i></a> <span class="paren3">(<span class="nonparen"><span class="paren4">(<span class="nonparen">split-point <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_member.html" class="symbol">member</a> '=&gt; format-arguments</span>)</span></span>)</span></span>)</span>
<span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_whencm_unless.html" class="symbol">unless</a> split-point <span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_error.html" class="symbol">error</a> <span class="string">"Expected =&gt; part."</span></span>)</span></span>)</span>
<span class="paren3">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_multiple-value-bind.html" class="symbol">multiple-value-bind</a> <span class="paren4">(<span class="nonparen">command-arguments property-selection-arguments</span>)</span>
<span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/any_values.html" class="symbol">values</a> <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_ldiffcm_tailp.html" class="symbol">ldiff</a> format-arguments split-point</span>)</span> <span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/acc_rest.html" class="symbol">rest</a> split-point</span>)</span></span>)</span>
`<span class="paren4">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_format.html" class="symbol">format</a> <a href="https://www.cliki.net/site/HyperSpec/Body/any_nil.html" class="symbol">nil</a> <span class="string">"(~A | %{~A -join </span><span class="string">\"</span><span class="string">`0</span><span class="string">\"</span><span class="string">}) -join </span><span class="string">\"</span><span class="string">`v</span><span class="string">\"</span><span class="string">"</span>
<span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_format.html" class="symbol">format</a> <a href="https://www.cliki.net/site/HyperSpec/Body/any_nil.html" class="symbol">nil</a> ,control-string ,@command-arguments</span>)</span>
<span class="paren5">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/fun_format.html" class="symbol">format</a> <a href="https://www.cliki.net/site/HyperSpec/Body/any_nil.html" class="symbol">nil</a> ,@property-selection-arguments</span>)</span></span>)</span></span>)</span></span>)</span></span>)</span></span></div><p><h2>Usage examples</h2><p><div class="code"><span class="nonparen">? <span class="paren1">(<span class="nonparen">open-powershell</span>)</span>
#&lt;EXTERNAL-PROCESS <span class="paren1">(<span class="nonparen">powershell.exe -Command <a href="https://www.cliki.net/site/HyperSpec/Body/any_-.html" class="symbol">-</a></span>)</span>[#&lt;A Foreign Pointer #x7C4&gt;] <span class="paren1">(<span class="nonparen">RUNNING</span>)</span> #x2101A0216D&gt;</span></div><p>Now the <tt>*powershell*</tt> variable is set to a running PowerShell. Here's an example of piping commands to it: <tt>find-big-folders</tt> recursively looks for folders containing more than 500 files. Then it returns the full pathname and modification time for each such directory. The <tt>run-powershell*</tt> function takes care of parsing the command output.<p><div class="code"><span class="nonparen"><span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defun.html" class="symbol"><i><span class="symbol">defun</span></i></a> find-big-folders <span class="paren2">(<span class="nonparen">directory-name</span>)</span>
<span class="paren2">(<span class="nonparen">run-powershell* <span class="paren3">(<span class="nonparen">$ <span class="string">"Get-ChildItem '~A' -Recurse ~
| Where-Object {$_.PSIsContainer -eq $True} ~
| Where-Object {$_.GetFiles().Count -gt 500}"</span>
directory-name =&gt; <span class="string">"$_.FullName, $_.LastWriteTime"</span></span>)</span></span>)</span></span>)</span></span></div><p>Trying this on the directory where the <a href="CLHS.html" class="internal">HyperSpec</a> lives:<p><div class="code"><span class="nonparen">? <span class="paren1">(<span class="nonparen">find-big-folders <span class="string">"C:/HyperSpec"</span></span>)</span>
<span class="paren1">(<span class="nonparen"><span class="paren2">(<span class="nonparen"><span class="string">"C:</span><span class="string">\\</span><span class="string">HyperSpec</span><span class="string">\\</span><span class="string">Body"</span> <span class="string">"2/12/2020 8:03:53 AM"</span></span>)</span>
<span class="paren2">(<span class="nonparen"><span class="string">"C:</span><span class="string">\\</span><span class="string">HyperSpec</span><span class="string">\\</span><span class="string">Issues"</span> <span class="string">"2/12/2020 8:04:12 AM"</span></span>)</span></span>)</span></span></div><p>Another example: extracting links from an HTML page via <a href="https://ss64.com/ps/invoke-webrequest.html">Invoke-WebRequest</a>. This will signal an error if the page isn't accessible—namely, a Lisp condition of type <tt>powershell-error</tt>.<p><div class="code"><span class="nonparen"><span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defun.html" class="symbol"><i><span class="symbol">defun</span></i></a> get-links <span class="paren2">(<span class="nonparen">url</span>)</span>
<span class="paren2">(<span class="nonparen">run-powershell* <span class="paren3">(<span class="nonparen">$ <span class="string">"(Invoke-WebRequest '~A').Links"</span>
url =&gt; <span class="string">"$_.href, $_.innerHTML"</span></span>)</span></span>)</span></span>)</span></span></div><p>This will provide a list of <a href="Win32.html" class="internal">Win32</a> links:<p><div class="code"><span class="nonparen">? <span class="paren1">(<span class="nonparen">get-links <span class="string">"https://cliki.net/Win32"</span></span>)</span>
<span class="paren1">(<span class="nonparen"><span class="paren2">(<span class="nonparen"><span class="string">"https://github.com/Zulu-Inuoe/win32"</span> <span class="string">"win32"</span></span>)</span> <span class="paren2">(<span class="nonparen"><span class="string">"/CFFI"</span> <span class="string">"CFFI"</span></span>)</span>
<span class="paren2">(<span class="nonparen"><span class="string">"https://github.com/Lovesan/doors"</span> <span class="string">"Doors"</span></span>)</span> <span class="paren2">(<span class="nonparen"><span class="string">"/Windows"</span> <span class="string">"Windows"</span></span>)</span>
<span class="paren2">(<span class="nonparen"><span class="string">"https://github.com/quek/cl-win32ole/"</span> <span class="string">"cl-win32ole"</span></span>)</span>
<span class="paren2">(<span class="nonparen"><span class="string">"/SBCL"</span> <span class="string">"SBCL"</span></span>)</span> <span class="paren2">(<span class="nonparen"><span class="string">"/CLISP"</span> <span class="string">"CLISP"</span></span>)</span> <span class="paren2">(<span class="nonparen"><span class="string">"/cffi"</span> <span class="string">"cffi"</span></span>)</span>
<span class="paren2">(<span class="nonparen"><span class="string">"/trivial-garbage"</span> <span class="string">"trivial-garbage"</span></span>)</span>
<span class="paren2">(<span class="nonparen"><span class="string">"https://github.com/ailisp/Graphic-Forms"</span> <span class="string">"Graphic-Forms"</span></span>)</span>
<span class="paren2">(<span class="nonparen"><span class="string">"/Windows"</span> <span class="string">"Windows"</span></span>)</span> <span class="paren2">(<span class="nonparen"><span class="string">"/BSD"</span> <span class="string">"BSD"</span></span>)</span>
<span class="paren2">(<span class="nonparen"><span class="string">"https://github.com/sharplispers/cormanlisp"</span> <span class="string">"Corman Lisp"</span></span>)</span>
<span class="paren2">(<span class="nonparen"><span class="string">"/Common%20Lisp%20implementation"</span> <span class="string">"Common Lisp implementation"</span></span>)</span>
<span class="paren2">(<span class="nonparen"><span class="string">"/Win32"</span> <span class="string">"Current version"</span></span>)</span>
<span class="paren2">(<span class="nonparen"><span class="string">"/site/history?article=Win32"</span> <span class="string">"History"</span></span>)</span>
<span class="paren2">(<span class="nonparen"><span class="string">"/site/backlinks?article=Win32"</span> <span class="string">"Backlinks"</span></span>)</span>
<span class="paren2">(<span class="nonparen"><span class="string">"/site/edit-article?title=Win32&amp;amp;from-revision=3799349377"</span>
<span class="string">"Edit"</span></span>)</span>
<span class="paren2">(<span class="nonparen"><span class="string">"/site/edit-article?create=t"</span> <span class="string">"Create"</span></span>)</span> <span class="paren2">(<span class="nonparen"><span class="string">"/"</span> <span class="string">"Home"</span></span>)</span>
<span class="paren2">(<span class="nonparen"><span class="string">"/site/recent-changes"</span> <span class="string">"Recent Changes"</span></span>)</span> <span class="paren2">(<span class="nonparen"><span class="string">"/CLiki"</span> <span class="string">"About"</span></span>)</span>
<span class="paren2">(<span class="nonparen"><span class="string">"/Text%20Formatting"</span> <span class="string">"Text Formatting"</span></span>)</span> <span class="paren2">(<span class="nonparen"><span class="string">"/site/tools"</span> <span class="string">"Tools"</span></span>)</span>
<span class="paren2">(<span class="nonparen"><span class="string">"/site/register"</span> <span class="string">"register"</span></span>)</span></span>)</span></span></div><p>Then there's the <a href="monkeylib-atom.html" class="internal">Atom</a> feed format. <a href="Keeping&#32;up&#32;with&#32;CLiki.html" class="internal">CLiki uses it</a>. We can use <a href="XPath.html" class="internal">XPath</a> in PowerShell to select feed entries. Since Atom is a namespaced <a href="XML.html" class="internal">XML</a> format, this requires providing the <tt>Namespace</tt> option to <a href="https://ss64.com/ps/select-xml.html">Select-XML</a>:<p><div class="code"><span class="nonparen"><span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defparametercm_defvar.html" class="symbol"><i><span class="symbol">defparameter</span></i></a> <span class="special">*atom-entry-properties*</span>
<span class="comment">;; A few atom:entry properties, e.g. innerText gives the HTML content,
</span> <span class="comment">;; assuming that "html" is the value of the &lt;content type=""&gt; attribute.
</span> <span class="string">"$_.Node.updated, $_.Node.link.href, $_.Node.content.innerText"</span></span>)</span>
<span class="paren1">(<span class="nonparen"><a href="https://www.cliki.net/site/HyperSpec/Body/mac_defun.html" class="symbol"><i><span class="symbol">defun</span></i></a> get-atom-entries <span class="paren2">(<span class="nonparen">url</span>)</span>
<span class="paren2">(<span class="nonparen">run-powershell* <span class="paren3">(<span class="nonparen">$ <span class="string">"Select-XML -XPath '//atom:entry' -Namespace @{atom='http://www.w3.org/2005/Atom'} ~
-Content (Invoke-WebRequest '~A')"</span> url =&gt; <span class="special">*atom-entry-properties*</span></span>)</span></span>)</span></span>)</span></span></div><p><h2>A wrinkle</h2><p>There doesn't seem to be any obvious way to send Ctrl+C to PowerShell via IPC. So the problem is how to break out of a PowerShell command by signaling from Lisp.<p><hr>
<a href="Windows.html" class="category">Windows</a> <a href="IPC.html" class="category">IPC</a></div></div>
<div id="footer" class="buttonbar"><ul><li><a href="PowerShell.html">Current version</a></li>
<li><a href="https://www.cliki.net/site/history?article=PowerShell">History</a></li>
<li><a href="https://www.cliki.net/site/backlinks?article=PowerShell">Backlinks</a></li><li><a href="https://www.cliki.net/site/edit-article?title=PowerShell&amp;from-revision=3811003538">Edit</a></li><li><a href="https://www.cliki.net/site/edit-article?create=t">Create</a></li></ul></div>
</div>
<div id="header-buttons" class="buttonbar">
<ul>
<li><a href="https://www.cliki.net/">Home</a></li>
<li><a href="https://www.cliki.net/site/recent-changes">Recent Changes</a></li>
<li><a href="CLiki.html">About</a></li>
<li><a href="Text&#32;Formatting.html">Text Formatting</a></li>
<li><a href="https://www.cliki.net/site/tools">Tools</a></li>
</ul>
<div id="search">
<form action="https://www.cliki.net/site/search">
<label for="search_query" class="hidden">Search CLiki</label>
<input type="text" name="query" id="search_query" value="" />
<input type="submit" value="search" />
</form>
</div>
</div>
<div id="pageheader">
<div id="header">
<span id="logo">CLiki</span>
<span id="slogan">the common lisp wiki</span>
<div id="login"><form method="post" action="https://www.cliki.net/site/login">
<label for="login_name" class="hidden">Account name</label>
<input type="text" name="name" id="login_name" class="login_input" />
<label for= "login_password" class="hidden">Password</label>
<input type="password" name="password" id="login_password" class="login_input" />
<input type="submit" name="login" value="login" id="login_submit" /><br />
<div id="register"><a href="https://www.cliki.net/site/register">register</a></div>
<input type="submit" name="reset-pw" value="reset password" id="reset_pw" />
</form>
</div>
</div>
</div>
</body></html>