<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jung Hyun, Nam</title>
    <description>The latest articles on DEV Community by Jung Hyun, Nam (@rkttu).</description>
    <link>https://dev.to/rkttu</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F82693%2F3066a6a6-2539-48a5-8e61-d698a22dcd9b.png</url>
      <title>DEV Community: Jung Hyun, Nam</title>
      <link>https://dev.to/rkttu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rkttu"/>
    <language>en</language>
    <item>
      <title>What if calling Python from C# took 4 lines, supported Native AOT, and didn't need a project file?
Just shipped DotNetPy v0.5.0 — a lightweight Python interop library built for modern .NET.
📦 https://github.com/rkttu/dotnetpy</title>
      <dc:creator>Jung Hyun, Nam</dc:creator>
      <pubDate>Thu, 19 Mar 2026 07:01:43 +0000</pubDate>
      <link>https://dev.to/rkttu/what-if-calling-python-from-c-took-4-lines-supported-native-aot-and-didnt-need-a-project-file-2na8</link>
      <guid>https://dev.to/rkttu/what-if-calling-python-from-c-took-4-lines-supported-native-aot-and-didnt-need-a-project-file-2na8</guid>
      <description>&lt;p&gt;

&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://github.com/rkttu/dotnetpy" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopengraph.githubassets.com%2F8183b55a473a9623ab32eb873c567ed15707eccedda7a45a17991db1559feeb7%2Frkttu%2Fdotnetpy" height="auto" class="m-0"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://github.com/rkttu/dotnetpy" rel="noopener noreferrer" class="c-link"&gt;
            GitHub - rkttu/dotnetpy: Lightweight and AOT-compatible Python Interop Library · GitHub
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Lightweight and AOT-compatible Python Interop Library - rkttu/dotnetpy
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.githubassets.com%2Ffavicons%2Ffavicon.svg"&gt;
          github.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;




</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>python</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Introducing DotNetPy: Python Interop for Modern .NET, Reimagined</title>
      <dc:creator>Jung Hyun, Nam</dc:creator>
      <pubDate>Thu, 19 Mar 2026 06:58:50 +0000</pubDate>
      <link>https://dev.to/rkttu/introducing-dotnetpy-python-interop-for-modern-net-reimagined-32gi</link>
      <guid>https://dev.to/rkttu/introducing-dotnetpy-python-interop-for-modern-net-reimagined-32gi</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;.NET and Python are two of the most widely used platforms in enterprise software today, yet bringing them together has always been painful. Existing interop libraries either require heavy runtime dependencies, lack support for modern .NET features like Native AOT, or demand complex project configurations with Source Generators.&lt;/p&gt;

&lt;p&gt;If you've ever wanted to leverage Python's rich data science and ML ecosystem from a C# application — without leaving your .NET toolchain — you know the friction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DotNetPy&lt;/strong&gt; is my answer to that problem. Version 0.5.0 is now available on NuGet.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is DotNetPy?
&lt;/h2&gt;

&lt;p&gt;DotNetPy (pronounced &lt;em&gt;dot-net-pie&lt;/em&gt;) is a .NET library for executing Python code directly from C#. It wraps the Python C API behind a clean, minimal interface.&lt;/p&gt;

&lt;p&gt;Here's the entire "hello world":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Python&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetInstance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;temperatures&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="m"&gt;23.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;19.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;31.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;27.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;22.1&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteAndCapture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;@"
    import statistics
    result = {'mean': statistics.mean(data), 'stdev': statistics.stdev(data)}
"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;temperatures&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Mean: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;GetDouble&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mean"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="n"&gt;F1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;°C ± &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;GetDouble&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"stdev"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="n"&gt;F1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No separate &lt;code&gt;.py&lt;/code&gt; files. No Source Generators. No complex setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Another Interop Library?
&lt;/h2&gt;

&lt;p&gt;There are established options — pythonnet, CSnakes, IronPython. Each has strengths, but none was designed for where .NET is heading in 2025 and beyond. DotNetPy fills that gap with three design pillars:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Native AOT Support
&lt;/h3&gt;

&lt;p&gt;DotNetPy is the &lt;strong&gt;only&lt;/strong&gt; .NET-Python interop library that works with &lt;code&gt;PublishAot=true&lt;/code&gt;. If you're building self-contained, ahead-of-time compiled applications, DotNetPy won't hold you back. Neither pythonnet nor CSnakes support this today.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. File-based App Ready (.NET 10+)
&lt;/h3&gt;

&lt;p&gt;.NET 10 introduces file-based apps — run a single &lt;code&gt;.cs&lt;/code&gt; file with &lt;code&gt;dotnet run script.cs&lt;/code&gt;, no project file required. DotNetPy is designed to work in this scenario from day one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# No csproj needed&lt;/span&gt;
dotnet run my-analysis.cs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes it ideal for scripting, prototyping, and lightweight automation tasks where spinning up a full project is overkill.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Declarative uv Integration
&lt;/h3&gt;

&lt;p&gt;Managing Python environments from .NET has always been a manual, error-prone process. DotNetPy integrates with &lt;a href="https://github.com/astral-sh/uv" rel="noopener noreferrer"&gt;uv&lt;/a&gt;, the fast Python package manager, so you can declare your entire Python environment in C#:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PythonProject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithProjectName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"my-analysis"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithPythonVersion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;gt;=3.10"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDependencies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"numpy&amp;gt;=1.24.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"pandas&amp;gt;=2.0.0"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;InitializeAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// Downloads Python, creates venv, installs packages&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetExecutor&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"import numpy as np; print(np.mean([1,2,3]))"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One call to &lt;code&gt;InitializeAsync()&lt;/code&gt; handles Python download, virtual environment creation, and dependency installation. No more "works on my machine" issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Does It Compare?
&lt;/h2&gt;

&lt;p&gt;Here's a quick comparison with the existing ecosystem:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;DotNetPy&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;pythonnet&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;CSnakes&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;IronPython&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Native AOT&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File-based Apps&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Source Generator Required&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;uv Integration&lt;/td&gt;
&lt;td&gt;Built-in&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Supported&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bidirectional Calls&lt;/td&gt;
&lt;td&gt;C#→Py&lt;/td&gt;
&lt;td&gt;C#↔Py&lt;/td&gt;
&lt;td&gt;C#→Py&lt;/td&gt;
&lt;td&gt;C#↔Py&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learning Curve&lt;/td&gt;
&lt;td&gt;Very Low&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;DotNetPy deliberately focuses on the &lt;strong&gt;C# → Python&lt;/strong&gt; direction. If you need Python calling back into .NET objects, pythonnet remains the right choice. DotNetPy is for scenarios where .NET is the host and Python is the tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Built-in Security
&lt;/h2&gt;

&lt;p&gt;Executing dynamic code always carries risk. DotNetPy ships with a &lt;strong&gt;Roslyn analyzer&lt;/strong&gt; that detects potential code injection at compile time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ The analyzer flags this — user input as code&lt;/span&gt;
&lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userInput&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ Safe — user data passed as variables&lt;/span&gt;
&lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"result = sum(numbers)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"numbers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userNumbers&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a deliberate design choice: make the safe path easy and the dangerous path visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features at a Glance
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automatic Python Discovery&lt;/strong&gt; — cross-platform detection of installed Python distributions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Marshaling&lt;/strong&gt; — pass .NET arrays, dictionaries, and primitives to Python and back&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Variable Management&lt;/strong&gt; — capture, check, delete, and clear Python variables from C#&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free-threaded Python Support&lt;/strong&gt; — detects Python 3.13+ builds with &lt;code&gt;--disable-gil&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thread Safety&lt;/strong&gt; — automatic GIL management for safe concurrent access&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Install from NuGet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package DotNetPy &lt;span class="nt"&gt;--version&lt;/span&gt; 0.5.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Initialize and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;DotNetPy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;Python&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/path/to/python313.dll"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Python&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetInstance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sum([1,2,3,4,5])"&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nf"&gt;GetInt32&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 15&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or let DotNetPy find Python automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Python&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PythonDiscovery&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindPython&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Use Cases I'm Targeting
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI/ML integration&lt;/strong&gt;: Call scikit-learn, PyTorch, or Hugging Face models from a .NET service&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data analysis scripts&lt;/strong&gt;: Run pandas/numpy workloads inline without a separate Python service&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automation &amp;amp; scripting&lt;/strong&gt;: Use &lt;code&gt;.NET 10&lt;/code&gt; file-based apps as Python-capable scripts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Legacy modernization&lt;/strong&gt;: Gradually introduce Python capabilities into existing .NET applications&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;The roadmap includes embeddable Python support on Windows (for simplified deployment) and specialized optimizations for AI and data science workflows. This is v0.5.0 — the API is stabilizing, and feedback at this stage is especially valuable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/rkttu/dotnetpy" rel="noopener noreferrer"&gt;github.com/rkttu/dotnetpy&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NuGet&lt;/strong&gt;: &lt;a href="https://www.nuget.org/packages/DotNetPy" rel="noopener noreferrer"&gt;DotNetPy 0.5.0&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docs&lt;/strong&gt;: &lt;a href="https://github.com/rkttu/dotnetpy/blob/main/docs/USAGE.md" rel="noopener noreferrer"&gt;Usage Examples&lt;/a&gt; · &lt;a href="https://github.com/rkttu/dotnetpy/blob/main/docs/SECURITY.md" rel="noopener noreferrer"&gt;Security Guide&lt;/a&gt; · &lt;a href="https://github.com/rkttu/dotnetpy/blob/main/docs/COMPARISON.md" rel="noopener noreferrer"&gt;Comparison&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;License&lt;/strong&gt;: Apache 2.0&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you're a .NET developer who's been eyeing Python's ecosystem, give DotNetPy a try. Issues, stars, and feedback are all welcome.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>python</category>
      <category>csharp</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Make Your WSL Environment Programmable</title>
      <dc:creator>Jung Hyun, Nam</dc:creator>
      <pubDate>Sat, 10 Jul 2021 16:48:28 +0000</pubDate>
      <link>https://dev.to/rkttu/make-your-wsl-environment-programmable-fi5</link>
      <guid>https://dev.to/rkttu/make-your-wsl-environment-programmable-fi5</guid>
      <description>&lt;p&gt;Original Post: &lt;a href="https://cloudeveloper.net/make-your-wsl-environment-programmable-72be5907d1ff" rel="noopener noreferrer"&gt;https://cloudeveloper.net/make-your-wsl-environment-programmable-72be5907d1ff&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have been fascinated by WSL architecture since its debut. It has the elegant and beautiful architecture to achieve interoperability between Windows and the Linux world. Eventually, I dive into the WSL Win32 APIs, its registry model, and internal too.&lt;/p&gt;

&lt;p&gt;But there was only slight WSL API documentation and sample. Later, I realized that Microsoft does not intend to use the WSL API for general purposes but WSL distribution developers. Also, the CLI tool known as WSL.exe and distro launchers is moving parts (because each Windows 10 major release has different features, command-line options). So these situations make it hard to automate the WSL environment.&lt;/p&gt;

&lt;p&gt;After many trials and errors, I developed a small but effective automation tool called WSL SDK. This tool is an out-of-process style COM server so that you can access the SDK with any COM-supported language.&lt;br&gt;
In this article, I want to share the walkthrough of the WSL SDK to overcome the difficulties of using official Win32 WSL APIs.&lt;/p&gt;
&lt;h2&gt;
  
  
  Hidden treasures of WSL
&lt;/h2&gt;

&lt;p&gt;If you are interested in the WSL APIs, you might get a hint about the API. For example, the API WslLaunch returns an HRESULT code. A WSL-related COM interface is in its internal composition known as LxssUserSession, and this API wraps around the COM object.&lt;/p&gt;

&lt;p&gt;Sadly, the internal COM object was completely hiding by Microsoft, and it looks like it was pretty intended. I guess that there are reasonable decisions about this direction. However, its internal COM object also does not have documentation well.&lt;/p&gt;
&lt;h2&gt;
  
  
  Unkindness of the WSL APIs
&lt;/h2&gt;

&lt;p&gt;Because of that, there is well-known and by-design behavior about the WSL APIs. If you call the WSL APIs with P/Invoke via PowerShell, LINQPad, or any COM-enabled environment, you cannot reach any WSL APIs. Many enthusiasts tried the APIs, but there is no luck.&lt;br&gt;
And why is that? Those environments I mentioned already initiated with another CoInitializeSecurity call. Sadly, WSL APIs require a particular initialization parameter. And the CoInitializeSecurity called in somewhere; you can never invoke the CoInitializeSecurity again. To overcome this issue, inevitably, I should choose the out-of-process model.&lt;br&gt;
Excavating the old samples&lt;br&gt;
However, the out-of-process model makes cumbersome steps to use the API. You should check the existence of the process. You will have to define how to communicate with the external process such as pipe, internal networking, or any marshaling protocols. Moreover, this approach makes it hard to extend and maintain the API calls and functionalities.&lt;/p&gt;

&lt;p&gt;I stuck at this point so a long time. But, thanks to the old project named All-In-One Code Framework developed by Microsoft, I found a beautiful solution. Yes. The out-of-process COM server model! So I adapted the sample out-of-process COM server code, and it works like a charm.&lt;/p&gt;
&lt;h2&gt;
  
  
  Under the hood
&lt;/h2&gt;

&lt;p&gt;When the client application requests a WSL SDK service object via COM API, Windows automatically launches the executable file to obtain an appropriate object reference. Then, wrap it with a proxy interface, and the client application retrieves that reference. For better understanding, please look at the below picture.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1f6i983t1khey4btuza.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1f6i983t1khey4btuza.jpg" alt="Excerpted from http://docwiki.embarcadero.com/RADStudio/Sydney/en/In-process,_Out-of-process,_and_Remote_Servers" width="412" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Justly, WSL SDK executable file invokes CoInitializeAPI with a correct parameter to communicate with WSL APIs. Then start a message pump to handle external RPC requests and any Windows GUI-related requests. When an object reference is requested, its reference count will increase or decrease. Then the count reaches zero; the executable process will shut down. And again, another request arrived, the same round will occur again until unregistering the COM information from the registry.&lt;/p&gt;

&lt;p&gt;So the WSL SDK decouples the COM security model between the application's one and WSL's requirement. And process lifecycle management handled by the operating system's infrastructure and a reference count mechanism. Every WSL SDK client does not need to care about any details. They request a WSL SDK interface as usual, and all things are going well.&lt;/p&gt;
&lt;h2&gt;
  
  
  Comparing direct P/Invoke to the WSL API and using WSL SDK
&lt;/h2&gt;

&lt;p&gt;I will show a simple demonstration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl6c4i8uesu1m50enuiz8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl6c4i8uesu1m50enuiz8.png" alt="Comparing direct P/Invoke to the WSL API and using WSL SDK" width="800" height="477"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A PowerShell sample code looks like below. I excerpted a sample code from the GitHub issue WSL API does not work in PowerShell · Issue #4058 · microsoft/WSL (github.com).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Excerpted from https://github.com/microsoft/WSL/issues/4058&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Calling WslIsDistributionRegistered directrly (Ubuntu-20.04):'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Add-Type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-TypeDefinition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sh"&gt;@'
using System.Runtime.InteropServices;
public class wslutil
{
 [DllImport("wslapi.dll", CharSet = CharSet.Unicode)]
 public static extern uint WslIsDistributionRegistered([In, MarshalAs(UnmanagedType.LPWStr)] string distributionName);
public static void Main(string[] args)
 {
  System.Console.WriteLine(WslIsDistributionRegistered("Ubuntu-20.04"));
 }
}
'@&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;wslutil&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;({})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The PowerShell code references a C-function from the WSLAPI.dll. Seemingly, it makes sense and should work well. But the code returns zero, does not reflect the current status.&lt;/p&gt;

&lt;p&gt;However, WSL SDK returns the correct value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Calling WSL SDK API (Ubuntu-20.04):'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$DistroName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Ubuntu-20.04'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;New-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ComObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'WslSdk.WslService'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$Result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsDistroRegistered&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$DistroName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$Result&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essentially, both code depends on the WslIsDistributionRegistered function, but the PowerShell already calls the CoInitializeSecurity which does not meet requirements for WSL APIs. The first example will not work because of that.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Demo: Sandboxing WSL distro
&lt;/h2&gt;

&lt;p&gt;I will show another, more complex example script. The below code will automatically download the Alpine Linux root filesystem image from the official mirror. Then, add the VI improved editor to the distribution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="bp"&gt;$Error&lt;/span&gt;&lt;span class="n"&gt;ActionPreference&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Stop"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;New-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ComObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'WslSdk.WslService'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'A WslSdk.WslService object is created.'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Pause&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Get installed distro list&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Currently installed WSL distro list: '&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetDistroList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$list&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Pause&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Generate Random Name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$RandomName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GenerateRandomName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;$false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"We will use &lt;/span&gt;&lt;span class="nv"&gt;$RandomName&lt;/span&gt;&lt;span class="s2"&gt; as a new distro"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Download Alpine Linux RootFS Image&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Downloading alpine linux root file system image'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$TargetUrl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'https://dl-cdn.alpinelinux.org/alpine/v3.14/releases/x86_64/alpine-minirootfs-3.14.0-x86_64.tar.gz'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$RootfsFilePath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;TEMP&lt;/span&gt;&lt;span class="s2"&gt;\alpine.tar.gz"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$InstallPath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"C:\Distro\&lt;/span&gt;&lt;span class="nv"&gt;$RandomName&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Invoke-WebRequest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-UseBasicParsing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Uri&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$TargetUrl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-OutFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$RootfsFilePath&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Pause&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Register Distro&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Distro installation begins"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;" - Distro Name: &lt;/span&gt;&lt;span class="nv"&gt;$RandomName&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;" - Source RootFS File Path: &lt;/span&gt;&lt;span class="nv"&gt;$RootfsFilePath&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;" - Destination Install Path: &lt;/span&gt;&lt;span class="nv"&gt;$InstallPath&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RegisterDistro&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$RandomName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$RootfsFilePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$InstallPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Pause&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Distro Register Check&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$Result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsDistroRegistered&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$RandomName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Distro Name &lt;/span&gt;&lt;span class="nv"&gt;$RandomName&lt;/span&gt;&lt;span class="s2"&gt; Installed: &lt;/span&gt;&lt;span class="nv"&gt;$Result&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Pause&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Metadata Query&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Querying &lt;/span&gt;&lt;span class="nv"&gt;$RandomName&lt;/span&gt;&lt;span class="s2"&gt; metadata..."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$o&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;QueryDistroInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$RandomName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;" - Distro ID: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;$o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DistroId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;" - Distro Name: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;$o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DistroName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;" - Environment Variabls: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;$o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DefaultEnvironmentVariables&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;" - Default Uid: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;$o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DefaultUid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;" - Flags: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;$o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DistroFlags&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;" - Win32 Interop Enabled: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;$o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnableInterop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;" - Drive Mounting Enabled: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;$o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnableDriveMounting&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;" - NT Path Append Enabled: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;$o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AppendNtPath&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;" - WSL Version: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;$o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WslVersion&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Pause&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Run WSL command&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Installing vim..."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RunWslCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DistroName&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"apk add vim"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nx"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$res&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Pause&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Revealing launcher executable&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Revealing launcher executable file"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Start-Process&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-FilePath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;windir&lt;/span&gt;&lt;span class="s2"&gt;\explorer.exe"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ArgumentList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/select,&lt;/span&gt;&lt;span class="nv"&gt;$InstallPath&lt;/span&gt;&lt;span class="s2"&gt;\&lt;/span&gt;&lt;span class="nv"&gt;$RandomName&lt;/span&gt;&lt;span class="s2"&gt;.exe"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Pause&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Unregister Distro&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Unregister &lt;/span&gt;&lt;span class="nv"&gt;$RandomName&lt;/span&gt;&lt;span class="s2"&gt; distro..."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UnregisterDistro&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$RandomName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Pause&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Get installed distro list&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Currently installed WSL distro list: '&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetDistroList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$list&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Pause&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$obj&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$null&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is a basic root filesystem image does not design for the WSL. As you already know, WSL supports importing any Linux root filesystem image which meets exact processor architecture.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh4yhloqftlop5zu86rwu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh4yhloqftlop5zu86rwu.png" alt="Sandboxing WSL distro" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;WSL SDK handles dynamic distribution registration and manipulation even in the PowerShell environment.&lt;/p&gt;

&lt;p&gt;Just for fun, even in Microsoft Excel, you can interact with the WSL environment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fes587f80ouwao4fwjivn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fes587f80ouwao4fwjivn.png" alt="Running WSL SDK via Excel with VBA" width="800" height="554"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiir2pdici2gyqi4y7tmk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiir2pdici2gyqi4y7tmk.png" alt="Automating WSL in the Microsoft VB for Applications" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can access a variety of sample codes of WSL SDKs here: &lt;a href="https://github.com/wslhub/wsl-sdk-com/tree/main/sample" rel="noopener noreferrer"&gt;https://github.com/wslhub/wsl-sdk-com/tree/main/sample&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Future Roadmap
&lt;/h2&gt;

&lt;p&gt;I recently created a GitHub action pipeline thanks to the &lt;a href="https://github.com/marketplace/actions/setup-wsl" rel="noopener noreferrer"&gt;https://github.com/marketplace/actions/setup-wsl&lt;/a&gt; plugin and the GitHub team's decision to enable the WSL component in their Windows Server workload.&lt;/p&gt;

&lt;p&gt;Because of that, I could create a continuous integration for WSL SDK, which makes more confident releases. (&lt;a href="https://github.com/wslhub/wsl-sdk-com/actions/workflows/wsl-sdk-com-build.yml" rel="noopener noreferrer"&gt;https://github.com/wslhub/wsl-sdk-com/actions/workflows/wsl-sdk-com-build.yml&lt;/a&gt;) This work is a significant achievement of the WSL SDK roadmap.&lt;/p&gt;

&lt;p&gt;Moreover, my bucket list contains those goals.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Registration-free COM server (If possible)&lt;/li&gt;
&lt;li&gt;ARM64 native support&lt;/li&gt;
&lt;li&gt;Adopting WSL SDK to another of my previous project (WSL Manager)&lt;/li&gt;
&lt;li&gt;Various language wrappers (C#, Python, Go-lang, PowerShell, or any COM supported languages)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are interested in the WSL SDK project, please come and contribute to the GitHub repo. (&lt;a href="https://github.com/wslhub/wsl-sdk-com" rel="noopener noreferrer"&gt;https://github.com/wslhub/wsl-sdk-com&lt;/a&gt;)&lt;/p&gt;

</description>
      <category>wsl2</category>
      <category>linux</category>
      <category>windows</category>
      <category>devops</category>
    </item>
    <item>
      <title>Set up your SSH server in Windows 10 native way</title>
      <dc:creator>Jung Hyun, Nam</dc:creator>
      <pubDate>Sun, 02 Feb 2020 07:50:53 +0000</pubDate>
      <link>https://dev.to/rkttu/set-up-an-ssh-server-in-windows-10-native-way-22d9</link>
      <guid>https://dev.to/rkttu/set-up-an-ssh-server-in-windows-10-native-way-22d9</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/rkttu/set-up-ssh-key-and-git-integration-in-windows-10-native-way-o4i"&gt;Continuing from the last post&lt;/a&gt;, we'll look at how to set up a built-in SSH server starting with Windows 10 and Windows Server 1709. This method allows Windows Server to connect remotely using SSH, just like a traditional Linux server. We will also look at how you can use Remote Desktop securely without modifying your firewall settings using SSH port tunneling.&lt;/p&gt;

&lt;h1&gt;
  
  
  Installing and configuring OpenSSH Server
&lt;/h1&gt;

&lt;p&gt;You can install OpenSSH Server the same way you installed the SSH client in the previous article.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$OpenSSHServer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Get-WindowsCapability&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Online&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-like&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;OpenSSH.Server&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;Add-WindowsCapability&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Online&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$OpenSSHServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After installing the OpenSSH server program, start and stop the NT service once to create the necessary initial configuration files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$SSHDaemonSvc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Get-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;sshd&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;Start-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$SSHDaemonSvc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nx"&gt;Stop-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$SSHDaemonSvc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Apply asymmetric key authentication
&lt;/h1&gt;

&lt;p&gt;It is highly recommended that you use the public key authentication method and disable the password authentication method to prevent attacks through password assignment. To enable this authentication feature, start PowerShell as an administrator and open the file in the path below with notepad. (Or you can use another text editor of your choice.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nf"&gt;notepad.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;PROGRAMDATA&lt;/span&gt;&lt;span class="nx"&gt;\ssh\sshd_config&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For the following items, uncomment the items and apply the value as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PubkeyAuthentication yes&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PasswordAuthentication no&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PermitEmptyPasswords no&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then choose your preferred method of managing SSH public keys. Starting with Windows Server 2019 (or 1809), there are two ways to describe SSH public keys. One of which is the traditional way of creating an authorized_keys file in the user's home directory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using &lt;code&gt;$HOME\.ssh\authorized_keys&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;To use this method, comment out the following block of code at the bottom of the configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Match Group administrators
  AuthorizedKeysFile
  __PROGRAMDATA__/ssh/administrators_authorized_keys
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then go to the user home directory you want to log in to and create a &lt;code&gt;.ssh&lt;/code&gt; directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nf"&gt;mkdir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="bp"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;\.ssh"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Create an &lt;code&gt;authorized_keys&lt;/code&gt; file (without the extension) inside the newly created directory and open it with your favorite text editor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$authorizedKeyFilePath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="bp"&gt;$HOME&lt;/span&gt;&lt;span class="nf"&gt;\.ssh\authorized_keys&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;New-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$authorizedKeyFilePath&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;notepad.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$authorizedKeyFilePath&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Add the SSH public key value you are using here.&lt;/p&gt;

&lt;p&gt;When you save the file, you must change the file permission settings as described in the section &lt;strong&gt;Setting File Permissions with Authentication Key Information&lt;/strong&gt;. If this setting is missing, the SSH connection will fail.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using &lt;code&gt;administrators_authorized_keys&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;This is the default used by OpenSSH included in Windows Server 2019 (1809). Instead of registering a new SSH key for each user, you can manage your files in one place.&lt;/p&gt;

&lt;p&gt;If you use this method, all public keys must be stored in the &lt;code&gt;$env: PROGRAMDATA\ssh\administrators_authorized_keys&lt;/code&gt; file, except for non-administrative users (that is, users who do not belong to the Administrators group). If you try, this setting will be used instead of the setting in your home directory, so if there is no key here, the connection will fail.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;administrators_authorized_keys&lt;/code&gt; file does not exist by default and must be created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$authorizedKeyFilePath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;ProgramData&lt;/span&gt;&lt;span class="nf"&gt;\ssh\administrators_authorized_keys&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;New-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$authorizedKeyFilePath&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;notepad.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$authorizedKeyFilePath&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Add the SSH public key value you are using here.&lt;/p&gt;

&lt;p&gt;When you save the file, you must change the file permission settings as described in the section &lt;strong&gt;Setting File Permissions with Authentication Key Information&lt;/strong&gt;. If this setting is missing, the SSH connection will fail.&lt;/p&gt;

&lt;h1&gt;
  
  
  Setting File Permissions with Authentication Key Information
&lt;/h1&gt;

&lt;p&gt;A common and very tough problem that you will face about using the OpenSSH server for Windows is this. SSH key file permission should have correct and limited file permission. Windows version of SSH also follows this rule, but especially in Windows, configuring file permission can be unintuitive.&lt;/p&gt;

&lt;p&gt;Depending on the method you chose in the previous step, you must verify the path of the &lt;code&gt;authorized_keys&lt;/code&gt; file or &lt;code&gt;administrators_authorized_keys&lt;/code&gt; file and change the permissions so that only the system account can access it using the &lt;code&gt;icacls.exe&lt;/code&gt; utility and the &lt;code&gt;Get-Acl&lt;/code&gt; and &lt;code&gt;Set-Acl&lt;/code&gt; commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$authorizedKeyFilePath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;icacls.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$authorizedKeyFilePath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/remove&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="nx"&gt;NT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;AUTHORITY\Authenticated&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Users&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;icacls.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$authorizedKeyFilePath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;/inheritance:r&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;Get-Acl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;ProgramData&lt;/span&gt;&lt;span class="nx"&gt;\ssh\ssh_host_dsa_key&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Set-Acl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$authorizedKeyFilePath&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Changing the SSH Default Shell
&lt;/h1&gt;

&lt;p&gt;Basically, for compatibility reasons, the Windows operating system has provided a shell-based interpreter that recognizes DOS commands for a long time. But now, with more and more features than working with DOS commands, PowerShell is becoming a good alternative.&lt;/p&gt;

&lt;p&gt;If necessary, you can specify that PowerShell as the default shell for SSH instead of the DOS interpreter. However, the settings here are specific to SSH sessions, not for the Remote Desktop or console session.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nf"&gt;New-ItemProperty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HKLM:\SOFTWARE\OpenSSH"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;DefaultShell&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;WINDIR&lt;/span&gt;&lt;span class="s2"&gt;\System32\WindowsPowerShell\v1.0\powershell.exe"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-PropertyType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Staring SSH Server
&lt;/h1&gt;

&lt;p&gt;You are now ready to start your SSH server. The SSH server is set to manual run by default, so you can change the startup mode to automatic. Then starts the service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$SSHDaemonSvc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Get-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;sshd&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;Set-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$SSHDaemonSvc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-StartupType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Automatic&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nx"&gt;Start-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$SSHDaemonSvc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LDgkf4-s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/4388/1%2AgJry9InM3arljQZjgdKP9A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LDgkf4-s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/4388/1%2AgJry9InM3arljQZjgdKP9A.png" alt="SSH to Windows Server"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations! From now, you can connect to Windows with SSH-key authentication.&lt;/p&gt;

&lt;h1&gt;
  
  
  How to Secure Remote Desktops
&lt;/h1&gt;

&lt;p&gt;Unlike Linux, Windows still runs much of the system on a graphical interface rather than on the command line. So if you try to do something with a terminal like this, you may not have much to do as you might expect.&lt;/p&gt;

&lt;p&gt;Remote Desktop, however, is a well-known food for many hackers and script kiddies as is well known. You may encounter the dilemma of choosing between convenience and security.&lt;/p&gt;

&lt;p&gt;Fortunately, SSH provides the concept of tunneling, supporting the ability to relay other network connections securely. Remote desktop connections can also be protected in this way so that you can use them with confidence.&lt;/p&gt;

&lt;p&gt;Start by blocking the TCP 3389 and UDP 3389 ports. You can do this because you will use Remote Desktop only with SSH tunneling.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nf"&gt;Set-NetFirewallRule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-DisplayName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="nx"&gt;Remote&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Desktop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Mode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UDP-In&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Block&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;Set-NetFirewallRule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-DisplayName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="nx"&gt;Remote&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Desktop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Mode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TCP-In&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Block&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, you must change the registry flag value so that the remote desktop server can accept the connection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nf"&gt;Set-ItemProperty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;HKLM:\System\CurrentControlSet\Control\Terminal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Server&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="nx"&gt;fDenyTSConnections&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And the part that I'm going to explain right now is really cool. As you saw earlier, you will not be asked for your password when you connect to OpenSSH, so you can set up a randomly generated strong password each time you use it. It is very useful to have a simple script in the system directory that can do this.&lt;/p&gt;

&lt;p&gt;Choose the type of script you want to create a file called &lt;code&gt;ChangePassword.ps1&lt;/code&gt;. We will keep the file in the system directory for your convenience.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$change_pwd_script_path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;WINDIR&lt;/span&gt;&lt;span class="nf"&gt;\ChangePassword.ps1&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;Clear-Content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$change_pwd_script_path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ErrorAction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SilentlyContinue&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;notepad.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$change_pwd_script_path&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Set your desired password
&lt;/h2&gt;

&lt;p&gt;Create the contents of the &lt;code&gt;ChangePassword.ps1&lt;/code&gt; file as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$Password&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Read-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Prompt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Provide your new account password"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-AsSecureString&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;Set-LocalUser&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;UserName&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Password&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$Password&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;Clear-Variable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Password"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Detailed settings such as remote desktop settings, WinRM connection settings, and Windows Update can be controlled using the sconfig command."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This script allows you to enter your own password. However, unless you change the policy, you can only use passwords that pass the Windows Server enhanced default password rules. You must specify a password that must meet all of the following conditions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;English capital letters (A through Z)&lt;/li&gt;
&lt;li&gt;Lowercase English letters (a through z)&lt;/li&gt;
&lt;li&gt;Arabic numerals (0 to 9)&lt;/li&gt;
&lt;li&gt;Special symbols (e.g.!, $, #,%)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Generate a new password every time
&lt;/h2&gt;

&lt;p&gt;Create the contents of the &lt;code&gt;ChangePassword.ps1&lt;/code&gt; file as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nf"&gt;Add-Type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-AssemblyName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;System.Web&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$Password&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;System.Web.Security.&lt;/span&gt;&lt;span class="kt"&gt;Membership&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="nf"&gt;GeneratePassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;Set-LocalUser&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;UserName&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Password&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$Password&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;ConvertTo-SecureString&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-AsPlainText&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Your New Password is:&lt;/span&gt;&lt;span class="se"&gt;`r`n`r`n&lt;/span&gt;&lt;span class="nv"&gt;$Password&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Detailed settings such as remote desktop settings, WinRM connection settings, and Windows Update can be controlled using the sconfig command."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;Clear-Variable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Password"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This way, you can set a strong password every time. If you forget your password, you can rest assured that you can still use public key authentication as a secondary means of authentication.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try logging in to Remote Desktop with Tunneling
&lt;/h2&gt;

&lt;p&gt;Now enter the following command to run the above script. After that, just set the password as guided by the script and verify that the remote desktop connection is working.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nf"&gt;ChangePassword&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To log in to the remote desktop, run SSH as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-L&lt;/span&gt; 3389:localhost:3389 &amp;lt;user_id&amp;gt;@&amp;lt;host_address&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The first 3389 is the port number on the server-side, and the second address is the port number you want to use locally. If you have changed the remote desktop's port number from the registry to another number on the server, you can enter the changed port number instead of 3389.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jOKYzAKh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/5912/1%2AO4WNnaXe9_LaeQ2Ed5s_6g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jOKYzAKh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/5912/1%2AO4WNnaXe9_LaeQ2Ed5s_6g.png" alt="Access to remote desktop using SSH tunneling with Remote Desktop 10 on macOS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you try to connect to a remote desktop using only the &lt;code&gt;&amp;lt;host_address&amp;gt;&lt;/code&gt; part as before, the firewall will block the connection as previously set up.  So no one can access the remote desktop directly unless the user has registered a public key that matches the SSH secret key with that server.&lt;/p&gt;

&lt;h1&gt;
  
  
  Using secure file sending and receiving
&lt;/h1&gt;

&lt;p&gt;Not surprisingly, it is possible to use SSH based SFTP. This feature can be used to securely handle large file transfers in place of the remote desktop's folder sharing feature.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uWj1M1nT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/5080/1%2AD-5vXZxRln1qBEFrzX0ihQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uWj1M1nT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/5080/1%2AD-5vXZxRln1qBEFrzX0ihQ.png" alt="Access to Windows Server using FileZilla's SFTP feature"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Any client that supports the SFTP feature, such as FileZilla, is compatible and has an management advantage, as there is no need to apply complex firewall open policies like traditional FTP.&lt;/p&gt;

&lt;h1&gt;
  
  
  Wrap-up
&lt;/h1&gt;

&lt;p&gt;This walks you through all the new SSH features that have been added since Windows 10 1709. Both articles are available for Windows 10 and Windows Server 2019, so please take a moment to set them up for even more security.&lt;/p&gt;

&lt;h1&gt;
  
  
  Credits
&lt;/h1&gt;

&lt;p&gt;The following articles helped me as I wrote this article.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ilovepowershell.com/2018/05/28/awesome-and-simple-way-to-generate-random-passwords-with-powershell/"&gt;https://ilovepowershell.com/2018/05/28/awesome-and-simple-way-to-generate-random-passwords-with-powershell/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/16212816/setting-up-openssh-for-windows-using-public-key-authentication"&gt;https://stackoverflow.com/questions/16212816/setting-up-openssh-for-windows-using-public-key-authentication&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>openssh</category>
      <category>sftp</category>
      <category>rdp</category>
      <category>windowsserver</category>
    </item>
    <item>
      <title>Set up SSH Key and Git integration in Windows 10 native way</title>
      <dc:creator>Jung Hyun, Nam</dc:creator>
      <pubDate>Sun, 27 Oct 2019 16:18:36 +0000</pubDate>
      <link>https://dev.to/rkttu/set-up-ssh-key-and-git-integration-in-windows-10-native-way-o4i</link>
      <guid>https://dev.to/rkttu/set-up-ssh-key-and-git-integration-in-windows-10-native-way-o4i</guid>
      <description>&lt;p&gt;Did you know that Windows 10 comes with an OpenSSH client?&lt;/p&gt;

&lt;p&gt;Starting with the Windows 10 Fall Creators Update (1709), OpenSSH clients are starting to be offered as Windows add-ons. However, it is easy to misunderstand that it is only provided by unfamiliar usage that differs from Linux, or that it is still not supported properly.&lt;/p&gt;

&lt;p&gt;In this article, we'll look at how to set up the commonly used client environment related to OpenSSH in a way that's built into Windows 10, and I'll give you some useful tips.&lt;/p&gt;

&lt;h1&gt;
  
  
  Configure Windows OpenSSH
&lt;/h1&gt;

&lt;p&gt;Start PowerShell as an administrator and use the PowerShell commands below to add Windows components.&lt;/p&gt;

&lt;p&gt;Microsoft's current installation of OpenSSH is an add-on package, Feature-On-Demand, not an item in the &lt;code&gt;Add/Remove Windows Components&lt;/code&gt; dialog box of the classic Control Panel &lt;code&gt;control.exe&lt;/code&gt;. You can install it only by using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$OpenSSHClient&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Get-WindowsCapability&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Online&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-like&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;OpenSSH.Client&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Add-WindowsCapability&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Online&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$OpenSSHClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Normally, no system restart is required after installation.&lt;/p&gt;

&lt;p&gt;After completing the installation, you may enable the ssh-agent service. This service is used to register to not ask for the SSH key password every time. Initially, the service is disabled and stopped, so set the service to autostart, and start it now.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$SSHAgentSvc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Get-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;ssh-agent&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Set-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$SSHAgentSvc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-StartupType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Automatic&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Start-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$SSHAgentSvc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should now close the PowerShell window in administrator mode and work with the PowerShell window open as normal.&lt;/p&gt;

&lt;p&gt;Since we are setting up a new system, let's create a new SSH key. Some common utilities have been added along with the OpenSSH client package. Run the &lt;code&gt;ssh-keygen&lt;/code&gt; command and answer questions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;ssh-keygen&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a key pair from the &lt;code&gt;$HOME\.ssh\id_rsa&lt;/code&gt; file and the &lt;code&gt;$HOME\.ssh\id_rsa.pub&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Now run the &lt;code&gt;ssh-add&lt;/code&gt; command to add this key pair to the ssh-agent service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;ssh-add&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It automatically registers the &lt;code&gt;$HOME\.ssh\id_rsa&lt;/code&gt; key pair, and now you can authenticate with that key pair.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Sometimes the system may have several &lt;code&gt;ssh.exe&lt;/code&gt; binary files installed, and the &lt;code&gt;ssh.exe&lt;/code&gt; binary path may be duplicated in the &lt;code&gt;PATH&lt;/code&gt; environment variable. To debug this problem, review the contents of the &lt;code&gt;path&lt;/code&gt; command or the &lt;code&gt;PATH&lt;/code&gt; environment variable and change the folder path containing the &lt;code&gt;ssh.exe&lt;/code&gt; binary to be used first, or keep only one.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Registering SSH Keys on Github
&lt;/h1&gt;

&lt;p&gt;You need to register the public key of this SSH Key Pair to Github or your Git repository.&lt;/p&gt;

&lt;p&gt;Enter the following PowerShell command to copy the public key value to register other systems.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-Content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$HOME&lt;/span&gt;&lt;span class="nx"&gt;\.ssh\id_rsa.pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Set-Clipboard&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this command, public key automatically entered on the clipboard.&lt;/p&gt;

&lt;p&gt;Then enter the following command to open the GitHub configuration page. (Or you can open the URL below directly in your preferred browser instead of your default browser.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Start-Process&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;https://github.com/settings/ssh/new&lt;/span&gt;&lt;span class="s1"&gt;'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, paste the public key from the clipboard and register it by adding a clear description of the key.&lt;/p&gt;

&lt;h1&gt;
  
  
  Install Git Client and SSH Client
&lt;/h1&gt;

&lt;p&gt;There are many ways to install the Git client, but I personally recommend the Chocolatey Package Manager as the most intuitive and easy way.&lt;/p&gt;

&lt;p&gt;The official Git client installation package exposes a lot of options that can cause side effects, so if you install it incorrectly, you may run into difficulties due to unintended features.&lt;/p&gt;

&lt;p&gt;First install the Chocolatey Package Manager if it is not already installed. Because this is a system-level addition of software, allow a few minutes to open a new PowerShell window as an administrator.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Set-ExecutionPolicy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Bypass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Scope&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Process&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;New-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;System.Net.WebClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DownloadString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;https://chocolatey.org/install.ps1&lt;/span&gt;&lt;span class="s1"&gt;'))
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now enter the command to install the Git for Windows client.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Often, if the Chocolatey.org website enters a regular checkout period, the installation may not proceed properly. In this case, check the Chocolatey.org website and try again later.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;choco&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-y&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Back in the regular PowerShell window, set the GIT_SSH environment variable. You must specify this environment variable so that Git clients can properly recognize SSH clients on Windows 10.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$SSHPath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Get-Command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;ssh.exe&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Source&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="nx"&gt;SetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;GIT_SSH&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$SSHPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Powering PowerShell with oh-my-posh
&lt;/h1&gt;

&lt;p&gt;As the name suggests, oh-my-posh is a Windows PowerShell version of oh-my-zsh that is popular on macOS and Linux these days. And interestingly, it supports some of the features that oh-my-zsh provides.&lt;/p&gt;

&lt;p&gt;First run the oh-my-posh installation script. It's listed in PowerShell's official module repository, so the commands are not complicated and simple.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Install-Module&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;posh-git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Scope&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CurrentUser&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Install-Module&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;oh-my-posh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Scope&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CurrentUser&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are installing on PowerShell Core for Windows (6.x or later), run the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Install-Module&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;PSReadLine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-AllowPrerelease&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Scope&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CurrentUser&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-SkipPublisherCheck&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Edit the Profile file so that the oh-my-posh shell can be loaded automatically when PowerShell starts. If you run the command below, the file will be created if it doesn't exist.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Test-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$PROFILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;New-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;File&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$PROFILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;notepad.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$PROFILE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following code at the end of the script and save it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Import-Module&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;posh-git&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Import-Module&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;oh-my-posh&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Set-Theme&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Paradox&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a side note, using a programming font with powerline patching looks pretty and doesn't break the glyphs. Run the following command again in an elevated PowerShell and update the console window's font settings with the D2Coding font.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Import-Module&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;posh-git&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Import-Module&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;oh-my-posh&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Set-Theme&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Paradox&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When all the settings are applied, you will see something like the picture below, and if you move the directory to the Git repository, you will see the branch name look good. This seems to have some assortment. 😎&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F4zs154z63bur997lse0d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F4zs154z63bur997lse0d.png" alt="oh-my-posh in action!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Appendix 1: Installing the Windows Terminal App
&lt;/h1&gt;

&lt;p&gt;You can go directly to the Windows Terminal app store page by running the following command in PowerShell: As is well known, using Windows Terminal gives you all the benefits of a modern CLI development environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Start-Process&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'https://www.microsoft.com/store/productId/9N0DX20HK701'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After installation, you can launch the Windows Terminal app directly with &lt;code&gt;wt.exe&lt;/code&gt; or &lt;code&gt;wt&lt;/code&gt; shortcuts. That is, on Windows, remember &lt;code&gt;wt&lt;/code&gt; instead of &lt;code&gt;cmd&lt;/code&gt;, &lt;code&gt;powershell&lt;/code&gt; or &lt;code&gt;pwsh&lt;/code&gt;. 😏&lt;/p&gt;

&lt;h1&gt;
  
  
  Appendix 2: For SourceTree
&lt;/h1&gt;

&lt;p&gt;Unfortunately, the Git client used by SourceTree does not work with the SSH Agent service provided by Windows. Instead, you can use the keys you created.&lt;br&gt;
In the SourceTree Options window, change the SSH client to OpenSSH as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fqabitx4yj5jgvekiomq0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fqabitx4yj5jgvekiomq0.png" alt="Setting up existing SSH key on SourceTree"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, verify that the SSH key is the same as the &lt;code&gt;$HOME\.ssh\id_rsa&lt;/code&gt; file created in the previous step. If it is different, specify it again.&lt;br&gt;
When done, press the OK button to save the settings.&lt;/p&gt;

&lt;h1&gt;
  
  
  Appendix 3: Integrating with Visual Studio Code
&lt;/h1&gt;

&lt;p&gt;If &lt;code&gt;GIT_SSH&lt;/code&gt; environment variable is registered properly, integration is completed without any special setting. However, even though you have completed the configuration, if you are still in progress without any message when performing git pull, you can run the &lt;code&gt;ssh-add -l&lt;/code&gt; command built-in terminal to check the connection status with the ssh-agent service.&lt;/p&gt;

</description>
      <category>windows10</category>
      <category>ssh</category>
      <category>git</category>
      <category>github</category>
    </item>
  </channel>
</rss>
