Created
December 6, 2025 16:59
-
-
Save mezhgano/d3f3e3f1896d529c52a6637872cc5a42 to your computer and use it in GitHub Desktop.
Windows — Fix SSH keys permissions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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 |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I'm having trouble using SSH keys due to incorrect file permissions:
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.