<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0"
     xmlns:atom="http://www.w3.org/2005/Atom"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Answer · Loosely Decoupled</title>
    <link>https://looselydecoupled.com/shape/answer/</link>
    <description>Answers to PowerShell, Windows Server and OpenSSH questions the docs skip, with the reasoning behind them. Answer first, discussion after.</description>
    <language>en-us</language>
    
    <copyright>© 2026 Emmanuel Tsouris</copyright>
    <lastBuildDate>Mon, 28 Sep 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://looselydecoupled.com/shape/answer/index.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <title>Read the GPS Location from Rivian Dashcam Video with ffprobe</title>
      <link>https://looselydecoupled.com/rivian-dashcam-gps-location-ffprobe/</link>
      <guid isPermaLink="true">https://looselydecoupled.com/rivian-dashcam-gps-location-ffprobe/</guid>
      <pubDate>Mon, 28 Sep 2026 00:00:00 +0000</pubDate>
      <dc:creator>Emmanuel Tsouris</dc:creator>
      <category>Automation</category>
      <category>Python</category>
      
      <description>A Rivian R1T dashcam clip carries one GPS fix, taken where its segment began, in the MP4 location tag, and ffprobe reads it in one command.</description>
      <content:encoded><![CDATA[<div class="answer" data-answer="true">
  <p class="answer__label" data-pagefind-ignore>TL;DR</p>
  <p>The GPS position is in the MP4 container&rsquo;s <code>location</code> tag. Read it with
ffprobe:</p>
<div class="console"><div class="code-block code-block--wrap console__command" data-copyable data-copy-label="command">
    <div class="code-block__head"><span class="code-block__lang">Command</span></div>
    <div class="code-block__scroll"><pre data-copy-source><code><span class="line"><span class="prompt">$ </span><span class="console__token">ffprobe</span> <span class="console__token">-v</span> <span class="console__token">error</span> <span class="console__token">-show_entries</span> <span class="console__token">format_tags=location</span> <span class="console__token">-of</span> <span class="console__token">default=nw=1:nk=1</span> <span class="console__token">\</span>
</span><span class="line">    <span class="console__token">&lt;clip&gt;.mp4</span></span></code></pre>
    </div>
  </div><div class="code-block code-block--wrap console__output">
    <p class="console__output-label">Output</p>
    <div class="code-block__scroll"><pre><code><span class="line"><span class="console__token">47.589462-122.2655</span></span></code></pre>
    </div>
  </div></div><p>The value is a signed latitude immediately followed by a signed longitude, in
decimal degrees: <code>47.589462</code> north, <code>-122.2655</code> west. That clip starts on the
I-90 floating bridge. <code>0,0</code> means the truck had no fix.</p>
<p>There is one fix per file, taken where the 15-minute segment began. There is
no per-second GPS track.</p>

</div>

<figure><img src="https://looselydecoupled.com/rivian-dashcam-gps-location-ffprobe/floating-bridge-segment-start_hu_2b5d759a1bdfb1b3.jpg" alt="The front camera half a second into a segment that begins on the I-90 floating bridge under an overcast sky, with two cars ahead and a distant skyline low on the horizon." width="1600" height="1280" loading="lazy" decoding="async"><figcaption>Half a second into the clip. Its tag reads 47.589462-122.2655: 47.589462, -122.2655. Plates blurred.</figcaption>
</figure>
<h2 id="spellings-of-the-tag">Spellings of the tag<a class="heading-anchor" href="https://looselydecoupled.com/rivian-dashcam-gps-location-ffprobe/#spellings-of-the-tag"
     aria-label="Link to section: Spellings of the tag" data-pagefind-ignore></a>
</h2>
<p>The value has no separator between the two numbers. The sign of the longitude
is the separator, so a parser has to split on the second <code>+</code> or <code>-</code>, not on a
comma or a space. The truck never writes a leading plus sign. Across 475
front-camera segments, all from encoder tag Rivian Firmware ver. 2022-47, three
spellings turned up, and <code>0,0</code> stands in when there is no fix:</p>
<dl class="facts">
  <dt>Usual</dt>
  <dd><code>47.589462-122.2655</code>, on 439 of the 475 segments.</dd>
  <dt>Trailing slash</dt>
  <dd>the same form ending in <code>/</code>, on the other 36.</dd>
  <dt>After ffmpeg copies the file</dt>
  <dd><code>+47.5894-122.2655/</code>, the ISO 6709 form, with a leading plus sign and four decimal places. This is ffmpeg&rsquo;s rewrite, not a firmware variant.</dd>
  <dt>No fix</dt>
  <dd><code>0,0</code>, which is a position in the Gulf of Guinea, not a reading.</dd>
</dl>

<p>ffprobe also prints a <code>location-eng</code> tag with the same value. Either one
works; the commands here read <code>location</code>.</p>
<h2 id="what-one-fix-per-segment-rules-out">What one fix per segment rules out<a class="heading-anchor" href="https://looselydecoupled.com/rivian-dashcam-gps-location-ffprobe/#what-one-fix-per-segment-rules-out"
     aria-label="Link to section: What one fix per segment rules out" data-pagefind-ignore></a>
</h2>
<p>The truck records one file per camera per 15-minute segment, and each file
carries a single fix from the moment that segment started. Nothing inside the
file records where the truck was a minute later. That rules out:</p>
<ul>
<li>A route drawn from the video. A segment gives you a point every 15 minutes,
which is too coarse to follow a road.</li>
<li>Speed. Two fixes 15 minutes apart give an average over the whole segment, not
the speed at any moment.</li>
<li>Finding a place by GPS alone. A drive across the floating bridge takes less
than a segment, so the bridge usually falls between two fixes.</li>
</ul>
<p>The five cameras of a segment each carry their own fix. In the clip earlier,
the front and rear files read <code>47.589462-122.2655</code> and the two side cameras and
the Gear Guard camera read <code>47.589474-122.2659</code>. Treat any one of them as the
segment&rsquo;s position.</p>
<p>To place a moment inside a segment, read the picture instead of the
container. <a href="https://looselydecoupled.com/find-landmark-dashcam-video-tunnel-light-color/">Finding a bridge in dashcam video by the color of tunnel
lights</a> locates the I-90
floating bridge crossing from the picture, where the GPS can&rsquo;t.</p>
<h2 id="parse-the-tag-in-python">Parse the tag in Python<a class="heading-anchor" href="https://looselydecoupled.com/rivian-dashcam-gps-location-ffprobe/#parse-the-tag-in-python"
     aria-label="Link to section: Parse the tag in Python" data-pagefind-ignore></a>
</h2>
<p><code>parse_location</code> returns a <code>(latitude, longitude)</code> tuple, or <code>None</code> when the
tag is missing, unreadable, or <code>0,0</code>. <code>read_location</code> runs ffprobe on one
file. The standard library is enough; Python 3.10 or later, for the <code>|</code> in the
type hints.</p>
<div class="code-block" data-copyable data-copy-label="rivian_location.py">
  <div class="code-block__head"><span class="code-block__lang code-block__file">rivian_location.py</span>
  </div>
  <div class="code-block__scroll">
    <div data-copy-source><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">re</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">subprocess</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">sys</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># A signed latitude immediately followed by a signed longitude. The leading</span>
</span></span><span class="line"><span class="cl"><span class="c1"># plus sign and the trailing slash are optional because not every writer</span>
</span></span><span class="line"><span class="cl"><span class="c1"># emits them.</span>
</span></span><span class="line"><span class="cl"><span class="n">LOCATION</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="sa">r</span><span class="s2">&#34;([+-]?\d+(?:\.\d+)?)([+-]\d+(?:\.\d+)?)&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">parse_location</span><span class="p">(</span><span class="n">tag</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">float</span><span class="p">,</span> <span class="nb">float</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">match</span> <span class="o">=</span> <span class="n">LOCATION</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">tag</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="ow">not</span> <span class="k">match</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="kc">None</span>
</span></span><span class="line"><span class="cl">    <span class="n">latitude</span><span class="p">,</span> <span class="n">longitude</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="k">match</span><span class="p">[</span><span class="mi">1</span><span class="p">]),</span> <span class="nb">float</span><span class="p">(</span><span class="k">match</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># The truck writes 0,0 when it has no GPS fix.</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">latitude</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">longitude</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="kc">None</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">latitude</span><span class="p">,</span> <span class="n">longitude</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">read_location</span><span class="p">(</span><span class="n">clip</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">float</span><span class="p">,</span> <span class="nb">float</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">tag</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">run</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="p">[</span><span class="s2">&#34;ffprobe&#34;</span><span class="p">,</span> <span class="s2">&#34;-v&#34;</span><span class="p">,</span> <span class="s2">&#34;error&#34;</span><span class="p">,</span> <span class="s2">&#34;-show_entries&#34;</span><span class="p">,</span> <span class="s2">&#34;format_tags=location&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">         <span class="s2">&#34;-of&#34;</span><span class="p">,</span> <span class="s2">&#34;default=nw=1:nk=1&#34;</span><span class="p">,</span> <span class="n">clip</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="n">capture_output</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">check</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span><span class="o">.</span><span class="n">stdout</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">parse_location</span><span class="p">(</span><span class="n">tag</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&#34;__main__&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">clip</span> <span class="ow">in</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>
</span></span><span class="line"><span class="cl">        <span class="n">point</span> <span class="o">=</span> <span class="n">read_location</span><span class="p">(</span><span class="n">clip</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="n">clip</span><span class="p">,</span> <span class="s2">&#34;no fix&#34;</span> <span class="k">if</span> <span class="n">point</span> <span class="ow">is</span> <span class="kc">None</span> <span class="k">else</span> <span class="sa">f</span><span class="s2">&#34;</span><span class="si">{</span><span class="n">point</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">point</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">)</span></span></span></code></pre></div></div>
  </div>
</div><p>Pass it one or more clips:</p>
<div class="console"><div class="code-block code-block--wrap console__command" data-copyable data-copy-label="command">
    <div class="code-block__head"><span class="code-block__lang">Command</span></div>
    <div class="code-block__scroll"><pre data-copy-source><code><span class="line"><span class="prompt">$ </span><span class="console__token">python3</span> <span class="console__token">rivian_location.py</span> <span class="console__token">&lt;clip&gt;.mp4</span></span></code></pre>
    </div>
  </div><div class="code-block code-block--wrap console__output">
    <p class="console__output-label">Output</p>
    <div class="code-block__scroll"><pre><code><span class="line"><span class="console__token">&lt;clip&gt;.mp4</span> <span class="console__token">47.589462,</span> <span class="console__token">-122.2655</span></span></code></pre>
    </div>
  </div></div><p>The tests cover every spelling in the list earlier, a southern and eastern
position so both signs are exercised, and each way the tag can mean &ldquo;no fix&rdquo;:</p>
<div class="code-block" data-copyable data-copy-label="test_rivian_location.py">
  <div class="code-block__head"><span class="code-block__lang code-block__file">test_rivian_location.py</span>
  </div>
  <div class="code-block__scroll">
    <div data-copy-source><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">pytest</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">rivian_location</span> <span class="kn">import</span> <span class="n">parse_location</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@pytest.mark.parametrize</span><span class="p">((</span><span class="s2">&#34;tag&#34;</span><span class="p">,</span> <span class="s2">&#34;expected&#34;</span><span class="p">),</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="s2">&#34;47.589462-122.2655&#34;</span><span class="p">,</span> <span class="p">(</span><span class="mf">47.589462</span><span class="p">,</span> <span class="o">-</span><span class="mf">122.2655</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="s2">&#34;47.589462-122.2655/&#34;</span><span class="p">,</span> <span class="p">(</span><span class="mf">47.589462</span><span class="p">,</span> <span class="o">-</span><span class="mf">122.2655</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="s2">&#34;+47.5894-122.2655/&#34;</span><span class="p">,</span> <span class="p">(</span><span class="mf">47.5894</span><span class="p">,</span> <span class="o">-</span><span class="mf">122.2655</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="s2">&#34;-33.8688+151.2093/&#34;</span><span class="p">,</span> <span class="p">(</span><span class="o">-</span><span class="mf">33.8688</span><span class="p">,</span> <span class="mf">151.2093</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl"><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">test_reads_each_spelling_of_the_tag</span><span class="p">(</span><span class="n">tag</span><span class="p">,</span> <span class="n">expected</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">assert</span> <span class="n">parse_location</span><span class="p">(</span><span class="n">tag</span><span class="p">)</span> <span class="o">==</span> <span class="n">expected</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@pytest.mark.parametrize</span><span class="p">(</span><span class="s2">&#34;tag&#34;</span><span class="p">,</span> <span class="p">[</span><span class="s2">&#34;&#34;</span><span class="p">,</span> <span class="s2">&#34;</span><span class="se">\n</span><span class="s2">&#34;</span><span class="p">,</span> <span class="s2">&#34;garbage&#34;</span><span class="p">,</span> <span class="s2">&#34;+0.0000+0.0000/&#34;</span><span class="p">,</span> <span class="s2">&#34;0-0&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">test_returns_none_for_no_fix</span><span class="p">(</span><span class="n">tag</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">assert</span> <span class="n">parse_location</span><span class="p">(</span><span class="n">tag</span><span class="p">)</span> <span class="ow">is</span> <span class="kc">None</span></span></span></code></pre></div></div>
  </div>
</div><div class="console"><div class="code-block code-block--wrap console__command" data-copyable data-copy-label="command">
    <div class="code-block__head"><span class="code-block__lang">Command</span></div>
    <div class="code-block__scroll"><pre data-copy-source><code><span class="line"><span class="prompt">$ </span><span class="console__token">python3</span> <span class="console__token">-m</span> <span class="console__token">pytest</span> <span class="console__token">-q</span></span></code></pre>
    </div>
  </div><div class="code-block code-block--wrap console__output">
    <p class="console__output-label">Output</p>
    <div class="code-block__scroll"><pre><code><span class="line"><span class="console__token">.........</span>                                                                <span class="console__token">[100%]</span>
</span><span class="line"><span class="console__token">9</span> <span class="console__token">passed</span> <span class="console__token">in</span> <span class="console__token">0.01s</span></span></code></pre>
    </div>
  </div></div><p>Dropping the optional sign from the latitude&rsquo;s half of the pattern fails the
southern-hemisphere case, so the tests do notice a broken pattern.</p>
<h2 id="remove-the-gps-location-from-a-clip-before-sharing-it">Remove the GPS location from a clip before sharing it<a class="heading-anchor" href="https://looselydecoupled.com/rivian-dashcam-gps-location-ffprobe/#remove-the-gps-location-from-a-clip-before-sharing-it"
     aria-label="Link to section: Remove the GPS location from a clip before sharing it" data-pagefind-ignore></a>
</h2>
<p>The tag travels with the file. A raw clip posted online tells anyone who
downloads it where it was recorded, and a folder of them maps where the truck
goes every day. Trimming the clip doesn&rsquo;t necessarily remove it: a stream copy
with ffmpeg kept the tag, rewritten in the <code>+…/</code> form, and exiftool reports it
as a GPS position:</p>
<div class="console"><div class="code-block code-block--wrap console__command" data-copyable data-copy-label="command">
    <div class="code-block__head"><span class="code-block__lang">Command</span></div>
    <div class="code-block__scroll"><pre data-copy-source><code><span class="line"><span class="prompt">$ </span><span class="console__token">ffmpeg</span> <span class="console__token">-i</span> <span class="console__token">&lt;clip&gt;.mp4</span> <span class="console__token">-t</span> <span class="console__token">2</span> <span class="console__token">-c</span> <span class="console__token">copy</span> <span class="console__token">copy.mp4</span>
</span><span class="line"><span class="prompt">$ </span><span class="console__token">exiftool</span> <span class="console__token">-G1</span> <span class="console__token">-a</span> <span class="console__token">&#34;-gps*&#34;</span> <span class="console__token">&#34;-location*&#34;</span> <span class="console__token">copy.mp4</span></span></code></pre>
    </div>
  </div><div class="code-block code-block--wrap console__output">
    <p class="console__output-label">Output</p>
    <div class="code-block__scroll"><pre><code><span class="line"><span class="console__token">[Composite]</span>     <span class="console__token">GPS</span> <span class="console__token">Altitude</span>                    <span class="console__token">:</span> <span class="console__token">0</span> <span class="console__token">m</span>
</span><span class="line"><span class="console__token">[Composite]</span>     <span class="console__token">GPS</span> <span class="console__token">Altitude</span> <span class="console__token">Ref</span>                <span class="console__token">:</span> <span class="console__token">Above</span> <span class="console__token">Sea</span> <span class="console__token">Level</span>
</span><span class="line"><span class="console__token">[Composite]</span>     <span class="console__token">GPS</span> <span class="console__token">Latitude</span>                    <span class="console__token">:</span> <span class="console__token">47</span> <span class="console__token">deg</span> <span class="console__token">35&#39;</span> <span class="console__token">22.02&#34;</span> <span class="console__token">N</span>
</span><span class="line"><span class="console__token">[Composite]</span>     <span class="console__token">GPS</span> <span class="console__token">Longitude</span>                   <span class="console__token">:</span> <span class="console__token">122</span> <span class="console__token">deg</span> <span class="console__token">15&#39;</span> <span class="console__token">55.76&#34;</span> <span class="console__token">W</span>
</span><span class="line"><span class="console__token">[Composite]</span>     <span class="console__token">GPS</span> <span class="console__token">Position</span>                    <span class="console__token">:</span> <span class="console__token">47</span> <span class="console__token">deg</span> <span class="console__token">35&#39;</span> <span class="console__token">22.02&#34;</span> <span class="console__token">N,</span> <span class="console__token">122</span> <span class="console__token">deg</span> <span class="console__token">15&#39;</span> <span class="console__token">55.76&#34;</span> <span class="console__token">W</span>
</span><span class="line"><span class="console__token">[UserData]</span>      <span class="console__token">Location</span> <span class="console__token">Information</span>            <span class="console__token">:</span> <span class="console__token">(none)</span> <span class="console__token">Role=shooting</span> <span class="console__token">Lat=47.58945</span> <span class="console__token">Lon=-122.26549</span> <span class="console__token">Alt=0.00</span> <span class="console__token">Body=earth</span> <span class="console__token">Notes=</span></span></code></pre>
    </div>
  </div></div><p>Other ways of writing a file behave differently. The <a href="https://looselydecoupled.com/ffmpeg-cut-multi-camera-dashcam-clips-in-sync/">multi-camera clips cut
with ffmpeg&rsquo;s concat demuxer</a>
came out with no <code>location</code> tag at all, because the demuxer drops file-level
metadata. The hyperlapse tool I used kept it, because it copies the
first source file&rsquo;s metadata on purpose. Check
each file rather than trusting the tool. To drop the container&rsquo;s metadata while copying,
add <code>-map_metadata -1</code>; the same exiftool command then prints nothing:</p>
<div class="console"><div class="code-block code-block--wrap console__command" data-copyable data-copy-label="command">
    <div class="code-block__head"><span class="code-block__lang">Command</span></div>
    <div class="code-block__scroll"><pre data-copy-source><code><span class="line"><span class="prompt">$ </span><span class="console__token">ffmpeg</span> <span class="console__token">-i</span> <span class="console__token">&lt;clip&gt;.mp4</span> <span class="console__token">-t</span> <span class="console__token">2</span> <span class="console__token">-c</span> <span class="console__token">copy</span> <span class="console__token">-map_metadata</span> <span class="console__token">-1</span> <span class="console__token">strip.mp4</span>
</span><span class="line"><span class="prompt">$ </span><span class="console__token">exiftool</span> <span class="console__token">-G1</span> <span class="console__token">-a</span> <span class="console__token">&#34;-gps*&#34;</span> <span class="console__token">&#34;-location*&#34;</span> <span class="console__token">strip.mp4</span></span></code></pre>
    </div>
  </div></div><p>Empty output is the result you want. Run the check on the file you&rsquo;re about
to upload, not on its source: each tool between the two can keep the tag or
drop it.</p>
<div class="tested" id="tested">
  <p class="label label--seam">Tested with</p><dl class="tested__rows">
    <div class="tested__row"><dt>ffprobe</dt> <dd>9.0.1</dd></div>
    <div class="tested__row"><dt>exiftool</dt> <dd>13.55</dd></div>
    <div class="tested__row"><dt>Python</dt> <dd>3.12.11</dd></div>
    <div class="tested__row"><dt>pytest</dt> <dd>9.1.1</dd></div>
    <div class="tested__row"><dt>OS</dt> <dd>macOS 27.0</dd></div>
    <div class="tested__row"><dt>Footage</dt> <dd>Rivian, encoder tag Rivian Firmware ver. 2022-47</dd></div>
    <div class="tested__row"><dt>Date</dt> <dd>October 2026</dd></div>
  </dl>
</div>
]]></content:encoded>
    </item>
    
    <item>
      <title>How to Show File Extensions in File Explorer with PowerShell</title>
      <link>https://looselydecoupled.com/show-file-extensions-windows-powershell/</link>
      <guid isPermaLink="true">https://looselydecoupled.com/show-file-extensions-windows-powershell/</guid>
      <pubDate>Sat, 04 Nov 2023 00:00:00 +0000</pubDate>
      <dc:creator>Emmanuel Tsouris</dc:creator>
      <category>Windows Server</category>
      <category>PowerShell</category>
      <category>Automation</category>
      
      <description>HideFileExt set to 0 shows file extensions for your account, and one Active Setup entry sets it for every account on the machine at its next sign-in.</description>
      <content:encoded><![CDATA[<div class="answer" data-answer="true">
  <p class="answer__label" data-pagefind-ignore>TL;DR</p>
  <p>For the account you are signed in as:</p>
<div class="code-block code-block--wrap" data-copyable data-copy-label="PowerShell">
  <div class="code-block__head"><span class="code-block__lang">PowerShell</span>
  </div>
  <div class="code-block__scroll">
    <div data-copy-source><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nv">$advanced</span> <span class="p">=</span> <span class="s1">&#39;HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">Set-ItemProperty</span> <span class="n">-Path</span> <span class="nv">$advanced</span> <span class="n">-Name</span> <span class="n">HideFileExt</span> <span class="n">-Value</span> <span class="mf">0</span> <span class="n">-Type</span> <span class="n">DWord</span>
</span></span><span class="line"><span class="cl"><span class="nb">Stop-Process</span> <span class="n">-Name</span> <span class="n">explorer</span> <span class="n">-Force</span></span></span></code></pre></div></div>
  </div>
</div><p>Windows restarts the shell, and every window now shows <code>report.txt.exe</code> as
what it is. Run it unelevated: the setting is per user and lives in the hive
of whoever runs the command, and an unelevated session can only stop its own
Explorer.</p>

</div>

<p>Windows hides the extension of known file types by default, so <code>invoice.pdf</code>
and <code>invoice.pdf.exe</code> look the same in Explorer. Turning that off is the first
thing to do on any machine you&rsquo;ll administer from the desktop, and the
setting is one DWORD.</p>
<h2 id="where-the-setting-lives">Where the setting lives<a class="heading-anchor" href="https://looselydecoupled.com/show-file-extensions-windows-powershell/#where-the-setting-lives"
     aria-label="Link to section: Where the setting lives" data-pagefind-ignore></a>
</h2>
<div class="code-block" data-copyable data-copy-label="Text">
  <div class="code-block__head"><span class="code-block__lang">Text</span>
  </div>
  <div class="code-block__scroll">
    <div data-copy-source><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced
</span></span><span class="line"><span class="cl">    HideFileExt    REG_DWORD    0 = show extensions, 1 = hide</span></span></code></pre></div></div>
  </div>
</div><p>Explorer reads the value when it starts, which is why the answer restarts it:
a write from PowerShell notifies nothing, and open windows stay as they were.
Stopping it with <code>Stop-Process -Name explorer</code> ends the shell process;
Winlogon relaunches it (<code>AutoRestartShell</code>, on by default), so the taskbar is
back within a second or two.</p>
<div class="admonition admonition--warning" role="note">
  <p class="admonition__label">
    <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><use href="https://looselydecoupled.com/show-file-extensions-windows-powershell/#i-triangle-alert"/></svg>
    <span>Warning</span>
  </p>
  <p>Elevated, <code>Stop-Process -Name explorer -Force</code> stops every user&rsquo;s Explorer
on the machine, not only yours — on a server with other people signed in
over RDP, that is their desktop vanishing. From an elevated session, stop
only the one in your session:</p>
<div class="code-block" data-copyable data-copy-label="PowerShell">
  <div class="code-block__head"><span class="code-block__lang">PowerShell</span>
  </div>
  <div class="code-block__scroll">
    <div data-copy-source><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">Get-Process</span> <span class="n">-Name</span> <span class="n">explorer</span> <span class="p">|</span>
</span></span><span class="line"><span class="cl">    <span class="nb">Where-Object</span> <span class="n">SessionId</span> <span class="o">-eq</span> <span class="p">(</span><span class="nb">Get-Process</span> <span class="n">-Id</span> <span class="nv">$PID</span><span class="p">).</span><span class="py">SessionId</span> <span class="p">|</span>
</span></span><span class="line"><span class="cl">    <span class="nb">Stop-Process</span> <span class="n">-Force</span></span></span></code></pre></div></div>
  </div>
</div>
</div><!-- style-check: procedure -->
<h2 id="for-every-account-including-ones-that-do-not-exist-yet">For every account, including ones that do not exist yet<a class="heading-anchor" href="https://looselydecoupled.com/show-file-extensions-windows-powershell/#for-every-account-including-ones-that-do-not-exist-yet"
     aria-label="Link to section: For every account, including ones that do not exist yet" data-pagefind-ignore></a>
</h2>
<p><code>HKCU</code> is the current user&rsquo;s hive, so the command above changes one account.
On a server where several administrators sign in, put the same command where
Windows runs it once for each user at their next sign-in, before Explorer
starts. That is Active Setup, and it is a key under <code>HKLM</code>, so it is set with
the registry provider from an elevated session:</p>
<div class="code-block" data-copyable data-copy-label="PowerShell">
  <div class="code-block__head"><span class="code-block__lang">PowerShell</span>
  </div>
  <div class="code-block__scroll">
    <div data-copy-source><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nv">$stub</span> <span class="p">=</span> <span class="s1">&#39;HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\ShowFileExtensions&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">New-Item</span> <span class="n">-Path</span> <span class="nv">$stub</span> <span class="n">-Force</span> <span class="p">|</span> <span class="nb">Out-Null</span>
</span></span><span class="line"><span class="cl"><span class="nb">Set-ItemProperty</span> <span class="n">-Path</span> <span class="nv">$stub</span> <span class="n">-Name</span> <span class="s1">&#39;(Default)&#39;</span>   <span class="n">-Value</span> <span class="s1">&#39;Show file extensions&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nb">Set-ItemProperty</span> <span class="n">-Path</span> <span class="nv">$stub</span> <span class="n">-Name</span> <span class="s1">&#39;IsInstalled&#39;</span> <span class="n">-Value</span> <span class="mf">1</span> <span class="n">-Type</span> <span class="n">DWord</span>
</span></span><span class="line"><span class="cl"><span class="nb">Set-ItemProperty</span> <span class="n">-Path</span> <span class="nv">$stub</span> <span class="n">-Name</span> <span class="s1">&#39;Version&#39;</span>     <span class="n">-Value</span> <span class="s1">&#39;1&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$advanced</span> <span class="p">=</span> <span class="s1">&#39;HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced&#39;</span>
</span></span><span class="line"><span class="cl"><span class="nv">$command</span> <span class="p">=</span> <span class="s2">&#34;Set-ItemProperty -Path &#39;</span><span class="nv">$advanced</span><span class="s2">&#39; -Name HideFileExt -Value 0&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">Set-ItemProperty</span> <span class="n">-Path</span> <span class="nv">$stub</span> <span class="n">-Name</span> <span class="s1">&#39;StubPath&#39;</span> <span class="n">-Value</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;powershell.exe -NoProfile -WindowStyle Hidden -Command &#34;&#39;</span> <span class="p">+</span> <span class="nv">$command</span> <span class="p">+</span> <span class="s1">&#39;&#34;&#39;</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span></span></span></code></pre></div></div>
  </div>
</div><p>At each sign-in Windows compares <code>Version</code> here against the copy under that
user&rsquo;s <code>HKCU\Software\Microsoft\Active Setup\Installed Components</code>. When the
user has none, or an older one, it runs <code>StubPath</code> as that user and records
the version. So the command runs once per account: existing accounts at their
next sign-in, new accounts at their first. It runs while the shell is still
starting, before the desktop is shown, so the first Explorer window a user
opens already shows extensions. To run it again for everyone, raise <code>Version</code>;
to stop it running for anyone new, delete the key under <code>HKLM</code>. Users who
already ran it keep the setting either way.</p>
<p>A console window can flash for a moment at sign-in while the stub runs;
<code>-WindowStyle Hidden</code> hides it as soon as PowerShell has started, not before.</p>
<p>This is the whole mechanism Windows uses to seed per-user settings from a
machine-wide install. It is the one route to &ldquo;every account&rdquo; that needs no
hive loading and no tool outside PowerShell. Group Policy Preferences does the
same job on a domain-joined machine.</p>
<!-- style-check: end procedure -->
<h2 id="common-failures">Common failures<a class="heading-anchor" href="https://looselydecoupled.com/show-file-extensions-windows-powershell/#common-failures"
     aria-label="Link to section: Common failures" data-pagefind-ignore></a>
</h2>
<h3 id="value-is-0-and-extensions-are-still-hidden">Value is <code>0</code> and extensions are still hidden<a class="heading-anchor" href="https://looselydecoupled.com/show-file-extensions-windows-powershell/#value-is-0-and-extensions-are-still-hidden"
     aria-label="Link to section: Value is 0 and extensions are still hidden" data-pagefind-ignore></a>
</h3>
<p>You ran the command elevated as a different account. An elevated PowerShell
opened with &ldquo;Run as administrator&rdquo; and a second set of credentials writes to
that account&rsquo;s <code>HKCU</code>, not yours. Run it unelevated in your own session.</p>
<h3 id="taskbar-didnt-come-back-after-stop-process">Taskbar didn&rsquo;t come back after <code>Stop-Process</code><a class="heading-anchor" href="https://looselydecoupled.com/show-file-extensions-windows-powershell/#taskbar-didnt-come-back-after-stop-process"
     aria-label="Link to section: Taskbar didn’t come back after Stop-Process" data-pagefind-ignore></a>
</h3>
<p><code>AutoRestartShell</code> is off on that machine, or the process was ended from
outside the session it belonged to. Start it by hand:</p>
<div class="code-block code-block--wrap" data-copyable data-copy-label="PowerShell">
  <div class="code-block__head"><span class="code-block__lang">PowerShell</span>
  </div>
  <div class="code-block__scroll">
    <div data-copy-source><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="nb">Start-Process</span> <span class="n">explorer</span></span></span></code></pre></div></div>
  </div>
</div><p>On Server Core there&rsquo;s no Explorer to stop and no setting to change;
<code>Stop-Process</code> reports that no such process exists.</p>
<h3 id="extensions-still-hidden-for-another-user">Extensions still hidden for another user<a class="heading-anchor" href="https://looselydecoupled.com/show-file-extensions-windows-powershell/#extensions-still-hidden-for-another-user"
     aria-label="Link to section: Extensions still hidden for another user" data-pagefind-ignore></a>
</h3>
<p>The user hasn&rsquo;t signed out and in since it was written; Active Setup runs at
sign-in and nowhere else. Or the stub ran under a policy that blocks
<code>powershell.exe</code> for that user. Check
<code>HKCU\Software\Microsoft\Active Setup\Installed Components\ShowFileExtensions</code>
in their hive: present means the stub was launched, absent means it wasn&rsquo;t.</p>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
