Skip to content

Commit 470e2bf

Browse files
Ajustes das pastas e scripts
1 parent 5b72257 commit 470e2bf

9 files changed

+306
-0
lines changed

.github/workflows/publish.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Publish PowerShell Gallery
2+
on:
3+
push:
4+
tags: ['v*']
5+
6+
jobs:
7+
publish:
8+
runs-on: windows-latest
9+
steps:
10+
- uses: actions/checkout@v4
11+
12+
- name: Setup PowerShell 7
13+
uses: actions/setup-powershell@v2
14+
with:
15+
pwsh-version: 7.4.x
16+
17+
- name: Install PSResourceGet
18+
shell: pwsh
19+
run: Install-Module Microsoft.PowerShell.PSResourceGet -Force -Scope CurrentUser
20+
21+
- name: Run Pester
22+
shell: pwsh
23+
run: Invoke-Pester -CI
24+
25+
- name: Publish Module
26+
shell: pwsh
27+
env:
28+
PSGALLERY_APIKEY: ${{ secrets.PSGALLERY_APIKEY }}
29+
run: Publish-PSResource -Path . -Repository PSGallery -ApiKey $env:PSGALLERY_APIKEY
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
2+
function Compress-FolderToTarGz {
3+
<#
4+
.SYNOPSIS
5+
Compacta diretório em .tar.gz usando tar + gzip.
6+
7+
.PARAMETER TargetDir
8+
Pasta a compactar (default: .).
9+
10+
.PARAMETER Exclude
11+
Itens a excluir (relativos).
12+
13+
.EXAMPLE
14+
Compress-FolderToTarGz -TargetDir C:\Projetos\App -Exclude @('.git','node_modules')
15+
#>
16+
[CmdletBinding(SupportsShouldProcess)]
17+
param(
18+
[string]$TargetDir = '.',
19+
[string[]]$Exclude
20+
)
21+
22+
$resolved = Resolve-Path $TargetDir
23+
$baseName = Split-Path $resolved -Leaf
24+
$parent = Split-Path $resolved -Parent
25+
$timestamp= Get-Date -Format 'yyyy-MM-dd_HH-mm-ss'
26+
$tarName = \"${baseName}_${timestamp}.tar\"
27+
$gzName = \"$tarName.gz\"
28+
$tarFull = Join-Path $parent $tarName
29+
$gzFull = Join-Path $parent $gzName
30+
31+
if ($PSCmdlet.ShouldProcess($TargetDir,\"Compress to $gzFull\")) {
32+
$excludeArgs = @()
33+
foreach ($ex in $Exclude) { $excludeArgs += \"--exclude=$ex\" }
34+
35+
Push-Location $parent
36+
& tar @excludeArgs -cf $tarFull $baseName
37+
if ($LASTEXITCODE) { throw 'tar falhou.' }
38+
39+
# gzip -9 se disponível, senão usa tar -czf direto
40+
if (Get-Command gzip -ErrorAction SilentlyContinue) {
41+
& gzip -9 $tarFull
42+
} else {
43+
& tar -czf $gzFull -C $parent $baseName
44+
Remove-Item $tarFull -Force
45+
}
46+
Pop-Location
47+
Write-Output $gzFull
48+
}
49+
}

Functions/Export-EnvBackup.ps1

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
2+
function Export-EnvBackup {
3+
<#
4+
.SYNOPSIS
5+
Faz dump completo das variáveis de ambiente (Sistema, Usuário e Perfil Default).
6+
7+
.DESCRIPTION
8+
Cria pasta timestampada, exporta três chaves do Registro para .reg e
9+
também gera .json para comparação.
10+
11+
.PARAMETER OutDir
12+
Diretório onde salvar o backup. Default: EnvBackup-<timestamp> no PWD.
13+
14+
.EXAMPLE
15+
Export-EnvBackup -OutDir D:\Backups
16+
#>
17+
[CmdletBinding(SupportsShouldProcess)]
18+
param(
19+
[string]$OutDir = (Join-Path $PWD ("EnvBackup-{0:yyyyMMdd-HHmmss}" -f (Get-Date)))
20+
)
21+
22+
if ($PSCmdlet.ShouldProcess('Environment', "Export to $OutDir")) {
23+
New-Item -ItemType Directory -Path $OutDir -Force | Out-Null
24+
25+
reg.exe export "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "$OutDir\SystemEnvironment.reg" /y
26+
reg.exe export "HKCU\Environment" "$OutDir\UserEnvironment.reg" /y
27+
reg.exe export "HKEY_USERS\.DEFAULT\Environment" "$OutDir\DefaultUserEnvironment.reg" /y
28+
29+
$jsonOpts = @{Depth = 3; Compress = $false}
30+
31+
Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment' |
32+
Select-Object -ExcludeProperty PS* |
33+
ConvertTo-Json @jsonOpts | Set-Content -Encoding UTF8 "$OutDir\SystemEnvironment.json"
34+
35+
Get-ItemProperty -Path 'HKCU:\Environment' |
36+
Select-Object -ExcludeProperty PS* |
37+
ConvertTo-Json @jsonOpts | Set-Content -Encoding UTF8 "$OutDir\UserEnvironment.json"
38+
39+
Get-ItemProperty -Path 'Registry::HKEY_USERS\.DEFAULT\Environment' -ErrorAction SilentlyContinue |
40+
Select-Object -ExcludeProperty PS* |
41+
ConvertTo-Json @jsonOpts | Set-Content -Encoding UTF8 "$OutDir\DefaultUserEnvironment.json"
42+
43+
Write-Output $OutDir
44+
}
45+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
2+
function Export-RegistrySelection {
3+
<#
4+
.SYNOPSIS
5+
Exporta entradas do Registro cujo Nome, Valor ou Dados contenham texto específico.
6+
7+
.PARAMETER TargetRoots
8+
Raízes a varrer (HKLM, HKCU, ...)
9+
10+
.PARAMETER Filters
11+
Texto ou array de textos a localizar.
12+
13+
.PARAMETER MatchFields
14+
Qual campo verificar: Key, Value ou Data.
15+
16+
.PARAMETER OutputDir
17+
Pasta onde salvar o .reg.
18+
19+
.PARAMETER Prefix / Suffix
20+
Prefixo/sufixo para o nome do arquivo.
21+
22+
.EXAMPLE
23+
Export-RegistrySelection -Filters "Open with" -MatchFields Value
24+
#>
25+
[CmdletBinding(SupportsShouldProcess)]
26+
param(
27+
[ValidateSet('HKEY_LOCAL_MACHINE','HKEY_CURRENT_USER','HKEY_CLASSES_ROOT','HKEY_USERS','HKEY_CURRENT_CONFIG')]
28+
[string[]]$TargetRoots = @('HKEY_LOCAL_MACHINE','HKEY_CURRENT_USER'),
29+
[string[]]$Filters = @('Open with','Edit with'),
30+
[ValidateSet('Key','Value','Data')]
31+
[string]$MatchFields = 'Data',
32+
[string]$OutputDir = (Join-Path $PWD 'RegistryExport'),
33+
[string]$Prefix,
34+
[string]$Suffix
35+
)
36+
37+
if (!(Test-Path $OutputDir)) { New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null }
38+
39+
$timestamp = Get-Date -Format 'yyyyMMdd-HHmmss'
40+
$fileBase = '{0}{1}{2}_{3}.reg' -f `
41+
($Prefix ?? ''), ($Prefix? '_':''), ($Suffix? ($Suffix+'_'):'') , $timestamp
42+
$filePath = Join-Path $OutputDir $fileBase
43+
44+
foreach ($root in $TargetRoots) {
45+
# usa reg query com /s pra percorrer
46+
$lines = & reg.exe query $root /s 2>$null
47+
foreach ($line in $lines) {
48+
$match = switch ($MatchFields) {
49+
'Key' { ($Filters | Where-Object { $line -like \"*$_*\" }).Count -gt 0 }
50+
default { ($Filters | Where-Object { $line -like \"*$_*\" }).Count -gt 0 }
51+
}
52+
if ($match) {
53+
$line | Out-File -Append -FilePath $filePath -Encoding Unicode
54+
}
55+
}
56+
}
57+
Write-Output $filePath
58+
}

Functions/Merge-EnvFromBackup.ps1

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
2+
function Merge-EnvFromBackup {
3+
<#
4+
.SYNOPSIS
5+
Compara um backup JSON e aplica adições/alterações seletivas nas variáveis de ambiente.
6+
7+
.PARAMETER BackupDir
8+
Pasta contendo SystemEnvironment.json e UserEnvironment.json gerados pelo Export-EnvBackup.
9+
10+
.EXAMPLE
11+
Merge-EnvFromBackup -BackupDir D:\Backups\EnvBackup-20250428-235812
12+
#>
13+
[CmdletBinding(SupportsShouldProcess)]
14+
param(
15+
[Parameter(Mandatory)][string]$BackupDir
16+
)
17+
18+
$bkSysPath = Join-Path $BackupDir 'SystemEnvironment.json'
19+
$bkUsrPath = Join-Path $BackupDir 'UserEnvironment.json'
20+
if (!(Test-Path $bkSysPath) -or !(Test-Path $bkUsrPath)) {
21+
throw "BackupDir não contém os arquivos JSON necessários."
22+
}
23+
24+
$bkSys = Get-Content $bkSysPath -Raw | ConvertFrom-Json
25+
$bkUsr = Get-Content $bkUsrPath -Raw | ConvertFrom-Json
26+
27+
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
28+
$rollbackDir = "EnvMergeRestore-$stamp"
29+
New-Item -ItemType Directory -Path $rollbackDir | Out-Null
30+
reg export "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" "$rollbackDir\System_before.reg" /y
31+
reg export "HKCU\Environment" "$rollbackDir\User_before.reg" /y
32+
33+
function Merge-Scope {
34+
param(
35+
[string]$ScopeName,
36+
[psobject]$Backup,
37+
[string]$RegPath
38+
)
39+
$current = Get-ItemProperty -Path $RegPath | Select-Object -ExcludeProperty PS*
40+
foreach ($prop in $Backup.PSObject.Properties) {
41+
$name = $prop.Name
42+
$value = $prop.Value
43+
if ($current.PSObject.Properties.Name -notcontains $name) {
44+
Write-Host "[$ScopeName] + $name" -ForegroundColor Green
45+
if ($PSCmdlet.ShouldProcess($name,"Add")) {
46+
Set-ItemProperty -Path $RegPath -Name $name -Value $value -Force
47+
}
48+
}
49+
elseif ($current.$name -ne $value) {
50+
Write-Host "[$ScopeName] ~ $name" -ForegroundColor Yellow
51+
Write-Host " Atual: $($current.$name)"
52+
Write-Host " Backup: $value"
53+
$ans = Read-Host 'Sobrescrever? (S/N)'
54+
if ($ans -match '^[sSyY]') {
55+
if ($PSCmdlet.ShouldProcess($name,"Replace")) {
56+
Set-ItemProperty -Path $RegPath -Name $name -Value $value -Force
57+
}
58+
}
59+
}
60+
}
61+
}
62+
63+
Merge-Scope 'SISTEMA' $bkSys 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment'
64+
Merge-Scope 'USUÁRIO' $bkUsr 'HKCU:\Environment'
65+
66+
# Broadcast WM_SETTINGCHANGE
67+
Add-Type @"
68+
using System;
69+
using System.Runtime.InteropServices;
70+
public class NativeMethods{
71+
[DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
72+
public static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam,
73+
uint fuFlags, uint uTimeout, out UIntPtr lpdwResult);
74+
}
75+
"@
76+
[NativeMethods]::SendMessageTimeout([intptr]0xFFFF,0x1A,[UIntPtr]::Zero,'Environment',2,1000,[ref]([UIntPtr]::Zero)) | Out-Null
77+
}

NicolasAigner.SystemToolkit.psd1

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
@{
2+
RootModule = 'NicolasAigner.SystemToolkit.psm1'
3+
ModuleVersion = '1.0.0'
4+
GUID = '8b2042b8-550d-46b7-b4b8-7b34154bae01'
5+
Author = 'Nícolas Aigner'
6+
CompanyName = 'Nícolas Aigner'
7+
Copyright = '(c) 2025 Nícolas Aigner'
8+
Description = 'Ferramentas PowerShell para backup/merge de variáveis de ambiente, exportação de registro e compactação tar.gz.'
9+
PowerShellVersion = '5.1'
10+
CompatiblePSEditions = @('Desktop','Core')
11+
FunctionsToExport = @('Export-EnvBackup','Merge-EnvFromBackup','Export-RegistrySelection','Compress-FolderToTarGz')
12+
CmdletsToExport = @()
13+
AliasesToExport = @()
14+
PrivateData = @{}
15+
}

NicolasAigner.SystemToolkit.psm1

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Auto‑loader: importa todas as funções do subdiretório Functions
2+
Get-ChildItem -Path (Join-Path $PSScriptRoot 'Functions') -Filter '*.ps1' | ForEach-Object {
3+
. $_.FullName
4+
Export-ModuleMember -Function $_.BaseName
5+
}

Tests/Export-EnvBackup.Tests.ps1

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
Describe 'Export-EnvBackup' {
3+
It 'Gera pasta e arquivos' {
4+
$tmp = Join-Path $env:TEMP ([Guid]::NewGuid())
5+
Export-EnvBackup -OutDir $tmp | Out-Null
6+
(Test-Path $tmp) | Should -BeTrue
7+
(Get-ChildItem $tmp | Measure-Object).Count | Should -BeGreaterThan 0
8+
Remove-Item $tmp -Recurse -Force
9+
}
10+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
PackageIdentifier: NicolasAigner.SystemToolkit
2+
PackageVersion: 1.0.0
3+
PackageName: NicolasAigner SystemToolkit
4+
Publisher: Nicolas Aigner
5+
PublisherUrl: https://github.com/nicolasaigner
6+
License: MIT
7+
LicenseUrl: https://opensource.org/licenses/MIT
8+
Homepage: https://github.com/nicolasaigner/SystemToolkit
9+
Installers:
10+
- Architecture: x64
11+
InstallerType: Powershell
12+
InstallerUrl: https://www.powershellgallery.com/api/v2/package/NicolasAigner.SystemToolkit/1.0.0
13+
InstallerSha256: FILL_ME_AFTER_PUBLISH
14+
Commands:
15+
- Export-EnvBackup
16+
- Merge-EnvFromBackup
17+
- Export-RegistrySelection
18+
- Compress-FolderToTarGz

0 commit comments

Comments
 (0)