Skip to content

Instantly share code, notes, and snippets.

@figueroadavid
Created February 29, 2024 23:07
Show Gist options
  • Save figueroadavid/5d1ef614f72a9ca2d7f8a0f6bf0ce3c9 to your computer and use it in GitHub Desktop.
Save figueroadavid/5d1ef614f72a9ca2d7f8a0f6bf0ce3c9 to your computer and use it in GitHub Desktop.
Backup a user's registry keys for WinSCP from HKEY_USERS
function Backup-ArbitraryWinSCPKey {
<#
.SYNOPSIS
This script backups a user's registry keys for WinSCP
.DESCRIPTION
Unlike the Backup-WinSCPKey, this script allows the user to backup an arbitrary user's
WinSCP key out of HKEY_USERS\<usersid>\Software\Martin Prikryl
.NOTES
This does require administrator rights, since the user will be delving into HKEY_USERS.
.PARAMETER SamAccountName
This is the login name of the user that will have their registry key backed up.
.PARAMETER UserAccountDomain
This is the domain for the user account, it defaults to the domain of the user running the script
.PARAMETER ExportDirectory
This is the directory where the exported file will be created.
The name of the file is WinSCP_<samaccountname>_<timestamp>.reg
.PARAMETER Overwrite
If the export file exists, this adds the /y switch to the reg export so that it will overwrite the file.
.PARAMETER Silent
This tells the script to not return the file object of the created export file
.PARAMETER OutputIsHKCU
This tells the script to convert the export files references to [HKEY_USERS\<usersid>] to [HKEY_CURRENT_USER]
making it suitable for the user to import their own keys.
.EXAMPLE
PS C:\> Backup-ArbitraryWinSCPKey -samAccountName User1 -ExportDirectory C:\temp -OutputIsHKCU
Directory: C:\temp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2/29/2024 4:48 PM 35422 WinSCP_User1_2024-02-29_164810.reg
#>
[cmdletbinding()]
param(
[parameter(Mandatory, ValueFromPipelineByPropertyName)]
[string]$SamAccountName,
[parameter(ValueFromPipelineByPropertyName)]
[string]$UserAccountDomain = $env:USERDOMAIN,
[parameter(Mandatory, ValueFromPipelineByPropertyName)]
[string]$ExportDirectory,
[parameter(ValueFromPipelineByPropertyName)]
[switch]$Overwrite,
[parameter(ValueFromPipelineByPropertyName)]
[switch]$Silent,
[parameter(ValueFromPipelineByPropertyName)]
[switch]$OutputIsHKCU
)
begin {
function Get-UserSID {
<#
.SYNOPSIS
Retrieves a user's security identifier without the need for the ActiveDirectory Module
.DESCRIPTION
Retrieves a user's security identifier without the need for the ActiveDirectory Module
.PARAMETER samAccountName
The actual samAccountName for the user whose account the SID should be retrieved.
.PARAMETER Domain
This is the domain of the account to be checked. It defaults to the domain of the user
running the script.
.NOTES
Thanks to @JBorean93 for this greatly simplified version
https://github.com/jborean93
.EXAMPLE
PS C:\> Get-UserSid -samAccountName User1
S-1-5-21-176475294-9861874819-1984720271-198576
#(The SID is completely made up)
#>
[CmdletBinding()]
param(
[parameter(Mandatory, ValueFromPipelineByPropertyName)]
[string]$samAccountName,
[parameter(ValueFromPipelineByPropertyName)]
[string]$Domain = $env:USERDOMAIN
)
try {
[System.Security.Principal.NTAccount]::new($Domain, $samAccountName).Translate(
[System.Security.Principal.SecurityIdentifier]).Value
}
catch {
throw 'Unable to locate the user in ActiveDirectory'
}
}
}
process {
$thisUserSID = Get-UserSID -samAccountName $SamAccountName -Domain $UserAccountDomain
$WinSCPPath = 'HKEY_USERS\{0}\SOFTWARE\Martin Prikryl' -f $thisUserSID
if (-not (test-Path -Path registry::$WinSCPPath)) {
throw ('Unable to find WinSCP key in HKU\<SID>, exiting')
}
$ExportPath = [System.IO.Path]::GetFullPath($ExportDirectory)
if (Test-Path -Path $ExportPath) {
$thisPath = Get-Item -Path $ExportPath
if ($thisPath -is [System.IO.DirectoryInfo]) {
Write-Verbose -Message ('$ExportDirectory ({0}) is a directory, continuing' -f $ExportPath)
}
else {
Throw ('The provided $ExportDirectory ({0}) is not a valid path, unable to continue' -f $ExportPath)
}
}
else {
throw ('$ExportDirectory ({0}) does not exist, unable to continue' -f $ExportDirectory)
}
$ExportFileName = 'WinSCP_{0}_{1}.reg' -f $env:USERNAME, [datetime]::Now.ToString('yyyy-MM-dd_HHmmss')
$FilePath = [system.io.path]::Combine($ExportDirectory, $ExportFileName)
$StartProcInfo = [System.Diagnostics.ProcessStartInfo]::new('reg.exe')
$StartProcInfo.CreateNoWindow = $true
$StartProcInfo.LoadUserProfile = $true
$StartProcInfo.UseShellExecute = $false
$StartProcInfo.RedirectStandardError = $true
$StartProcInfo.RedirectStandardOutput = $true
$StartProcInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
$ArgList = 'export "{0}" "{1}"' -f $WinSCPPath, $FilePath
if ($Overwrite) {
$StartProcInfo.Arguments = ('{0} /y' -f $ArgList)
}
else {
$StartProcInfo.Arguments = $ArgList
}
$Proc = [System.Diagnostics.Process]::new()
$Proc.StartInfo = $StartProcInfo
[void]$Proc.Start()
$Proc.WaitForExit()
$MyExitCode = $Proc.ExitCode
switch ($MyExitCode) {
0 { Write-Verbose -Message 'Successful'; break }
1 { Write-Warning -Message ($Proc.StandardError.ReadToEnd()); break }
2 { Write-Warning -Message 'Successful, but something is different{0}StdOut:{0}{1}{0}StdErr:{0}{2}' -f "`r`n", $Proc.StandardOutput.ReadToEnd(), $Proc.StandardError.ReadToEnd() }
}
if ($OutputIsHKCU) {
$OutputContent = Get-Content -Path $FilePath
$OutputContent = $OutputContent -replace ('HKEY_USERS\\{0}' -f $thisUserSID), 'HKEY_CURRENT_USER'
Set-Content -Path $FilePath -Value $OutputContent
}
if (-not $Silent) {
Get-Item -Path $FilePath
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment