Skip to content

Instantly share code, notes, and snippets.

@mezhgano
Created December 6, 2025 16:59
Show Gist options
  • Select an option

  • Save mezhgano/d3f3e3f1896d529c52a6637872cc5a42 to your computer and use it in GitHub Desktop.

Select an option

Save mezhgano/d3f3e3f1896d529c52a6637872cc5a42 to your computer and use it in GitHub Desktop.
Windows — Fix SSH keys permissions
# fix-ssh-permissions.ps1
# Automatically fixing SSH key permissions on Windows
# Usage:
# .\fix-ssh-permissions.ps1 # Fixes the entire .ssh folder
# .\fix-ssh-permissions.ps1 -FileName keyname # Fixes specific file
# .\fix-ssh-permissions.ps1 -Verbose # Verbose mode
# .\fix-ssh-permissions.ps1 -DryRun # Show what will be done (no changes)
param(
[Parameter(Mandatory=$false)]
[string]$FileName,
[Parameter(Mandatory=$false)]
[switch]$Recursive = $true,
[Parameter(Mandatory=$false)]
[switch]$DryRun
# Parameter is added by default by Powershell itself.
# [Parameter(Mandatory=$false)]
# [switch]$Verbose
)
# Checking administrator rights
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
Write-Host "❌ Administrator privileges required! Run PowerShell as administrator." -ForegroundColor Red
exit 1
}
# Fix specific file permissions
function Fix-FilePermissions {
param([string]$File)
if ($Verbose -or $DryRun) {
Write-Host "Processing file: $File" -ForegroundColor Cyan
}
if ($DryRun) {
Write-Host "[DryRun] Commands will be executed for: $File" -ForegroundColor Yellow
return
}
try {
# 1. Disable Inheritance
$null = Icacls $File /c /t /Inheritance:d
# 2. Set the owner to the current user
$null = TakeOwn /F $File
# 3. Grant full permissions to the current user
$null = Icacls $File /c /t /Grant:r "${env:UserName}:F"
# 4. Remove all remaining ACEs
$null = Icacls $File /c /t /Remove:g Administrator "Authenticated Users" BUILTIN\Administrators BUILTIN Everyone System Users
if ($Verbose) {
Write-Host "✅ Permissions fixed: $File" -ForegroundColor Green
}
}
catch {
Write-Host "❌ Error while processing $File : $_" -ForegroundColor Red
}
}
# Main
Write-Host "=== Fixing SSH Key Permissions on Windows ===" -ForegroundColor Magenta
if ($FileName) {
# Processing specific file
$KeyPath = "$env:UserProfile\.ssh\$FileName"
if (-not (Test-Path $KeyPath)) {
Write-Host "❌ File not found: $KeyPath" -ForegroundColor Red
Write-Host "Usage: .\fix-ssh-permissions.ps1 [-FileName <file_name>] [-Recursive] [-DryRun] [-Verbose]" -ForegroundColor Yellow
exit 1
}
Write-Host "Fixing permission for specific file: $FileName" -ForegroundColor Yellow
Fix-FilePermissions -File $KeyPath
# Also correct the .pub file if it exists.
$PubKeyPath = "$KeyPath.pub"
if (Test-Path $PubKeyPath) {
Fix-FilePermissions -File $PubKeyPath
}
}
else {
# Processing the entire .ssh folder
$SshDir = "$env:UserProfile\.ssh"
if (-not (Test-Path $SshDir)) {
Write-Host "❌ .ssh folder not found: $SshDir" -ForegroundColor Red
Write-Host "Create a folder and generate keys with command:" -ForegroundColor Yellow
Write-Host " ssh-keygen -t ed25519 -f $env:UserProfile\.ssh\id_ed25519" -ForegroundColor Cyan
exit 1
}
Write-Host "Fixing permission for entire folder: $SshDir" -ForegroundColor Yellow
if ($Recursive) {
# Process recursive
$items = Get-ChildItem -Path $SshDir -Recurse -Force -ErrorAction SilentlyContinue
}
else {
# Process only root files
$items = Get-ChildItem -Path $SshDir -Force -ErrorAction SilentlyContinue
}
$count = 0
foreach ($item in $items) {
# Skip Directories (process only files)
if (-not $item.PSIsContainer) {
Fix-FilePermissions -File $item.FullName
$count++
}
}
if ($DryRun) {
Write-Host "[DryRun] Files will be processed: $count" -ForegroundColor Yellow
}
else {
Write-Host "✅ Files processed: $count" -ForegroundColor Green
}
}
# Checking permissions
if (-not $DryRun) {
Write-Host "`n=== Checking permissions ===" -ForegroundColor Magenta
if ($FileName) {
$checkPath = "$env:UserProfile\.ssh\$FileName"
}
else {
$checkPath = "$env:UserProfile\.ssh\*"
}
Write-Host "Current permissions (First 5 files):"
Icacls $checkPath 2>$null | Select-Object -First 10
Write-Host "`n=== Check SSH connection ===" -ForegroundColor Magenta
Write-Host "Run command:"
Write-Host "ssh -i `$env:USERPROFILE\.ssh\id_ed25519 <user>@<server>" -ForegroundColor Cyan
}
Write-Host "`nDone." -ForegroundColor Green
@mezhgano
Copy link
Author

mezhgano commented Dec 6, 2025

I'm having trouble using SSH keys due to incorrect file permissions:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: UNPROTECTED PRIVATE KEY FILE! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions for 'private-key' are too open.

You can read more about this error here:
https://superuser.com/questions/1296024/windows-ssh-permissions-for-private-key-are-too-open
https://stackoverflow.com/questions/48888365/openssh-using-private-key-on-windows-unprotected-private-key-file-error

On the page at the second link, I found a PowerShell script for fixing permissions, but it wasn't particularly user-friendly, especially if I needed to fix multiple keys at once.

I then used AI to rewrite the script in a more user-friendly way, but i don't know PowerShell...
I tested the script on Windows 10 (19045), and it works.
If the script is dangerous or bad, please let me know in the comments or suggest corrections.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment