A registry PSmeghajtón keresztül történő kezelése nem teljesen tökéletes. Kiindulásként nézzük a Registry Editor-t. Itt felvettem egy SoosTibor nevű kulcsot a HKEY_CURRENT_USER ágban, néhány értékkel:
120 . ábra Az igazi bejegyzések a registryben
Ha ezeket kiolvassuk PowerShellel, akkor a következőket kapjuk:
[2] PS C:\> get-itemproperty HKCU:\SoosTibor
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\SoosTibor
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER
PSChildName : SoosTibor
PSDrive : HKCU
PSProvider : Microsoft.PowerShell.Core\Registry
uj : 1
Többsoros : {Első, Második, Harmadik}
Kifejtődő : soost
Amit láthatunk, hogy keverednek az igazi adatok a PowerShell által behozott tulajdonságokkal. Másrészt a kifejtődő szöveg típusú adat automatikusan kifejtődik, a tényleges adatot nem láthatjuk.
Nézzük tovább az adatok típusait is részletesebben:
[3] PS C:\> (get-itemproperty HKCU:\SoosTibor).uj
1
[4] PS C:\> (get-itemproperty HKCU:\SoosTibor).uj.gettype().fullname
System.Int32
[5] PS C:\> (get-itemproperty HKCU:\SoosTibor).többsoros.gettype().fullname
System.String[]
[6] PS C:\> (get-itemproperty HKCU:\SoosTibor).kifejtődő.gettype().fullname
System.String
Igazából nem látjuk, hogy az pontosan milyen típusú az adat a registry terminológiája szerint. Az ’uj’ DWORD? QWORD? Itt már teljesen .NETesítve van minden, ez például INT32-nek látszik. A ’többsoros’ és ’kifejtődő’ adatoknál szintén nem az igazat látjuk. Azaz, ha szeretnénk egy olyan szkriptet írni, amelyik lemásol értékeket egyik registry ágból egy másikba, nem biztos, hogy minden információ rendelkezésünkre áll. Nem beszélve a távoli eléréséről, azaz sajnos a PSmeghajtón keresztül nem tudjuk elérni más gépek registryjét.
Szerencsére a .NET keretrendszer itt is rendelkezésünkre áll, azon belül is a [Microsoft.Win32.RegistryKey ] osztály. Ennek van egy OpenRemoteBaseKey statikus és egy OpenSubKey ’rendes’ metódusa, melyekkel precízebben tudjuk kiolvasni a registry adatait.
Erre alapozottan készítettem a Get-Registry függvényt, amellyel egyszerűen tudjuk kiolvasni az „igazi” adatokat:
function Get-Registry{
param (
[Parameter(
Mandatory = $true,
Position = 0,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true,
HelpMessage = "Registry key path"
)]
[Alias("Path")]
[string]
$Name,
[Parameter(
Position = 1,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true
)]
[Alias("Machine")]
[string]
$Computer = $env:COMPUTERNAME,
[switch] $Expand
)
$basehash = @{
HKCU = "currentuser"
HKLM = "localmachine"
HKEY_CURRENT_USER = "currentuser"
HKEY_LOCAL_MACHINE = "localmachine"
}
$base, $path, $item = $name -split "\\(?!.+?\\)|:\\"
$base = $basehash.$base
try{
$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($base,$COMPUTER)
}
catch{
$reg = $null
Write-Host "Error accessing remote machine $computername" -ForegroundColor red
}
if($reg){
$exp = if($Expand){[microsoft.Win32.RegistryValueOptions]::None}
else{[microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames}
$x = $reg.OpenSubKey($path)
if($x){
$subkeys = $x.GetSubKeyNames() | %{
New-Object -TypeName PSObject -Property @{
Value = ""
Name = $_
Type = "Key"
}
}
$values = $x.GetValueNames() | ?{if($item -eq $null){$true}else{$_ -eq $item}} | %{
New-Object -TypeName PSObject -Property @{
Value = $x.GetValue($_,$null,$exp)
Name = if($_ -eq ""){"(default)"}else{$_}
Type = $x.GetValueKind($_)
}
}
@($subkeys) + @($values) |
Sort-Object -Property @{e={if($_.type -eq "Key"){0}else{1}}}, name |
Select-Object Name, Type, Value
}
}
}
Nézzük gyorsan végig, hogyan is működik ez a függvény! A paraméter-definícós részben a –Name (alias ‑Path) paraméter mellett lehetőség van a távoli –Computer meghatározására is. Emellett az ‑Expand paraméterrel beállíthatjuk, hogy a kifejtős szöveges adatokat tényleg kifejtve kapjuk meg.
Ezután készítettem egy kis szótárat, hogy az általánosan használatos registry-ág neveket használhassuk az OpenRemoteBaseKey statikus metódus másutt nem annyira használt elnevezése helyett. A PowerShelles HKCU és HKLM azért is jó nekünk, mert a TAB kiegészítés a mi függvényünknél is működni fog, így nagyon gyorsan lehet ezt a formát használva megadni az kulcsok neveit.
Ezután jön egy –split, mellyel szétválasztom a paraméterként átadott registry útvonalat $base, $path és $item részre. Itt fontos a függvény használatában, hogy ha az elérési út ’visszafeleperjelre’ végződik, akkor azt annak veszi, hogy mi a registry kulcs ’default’ értékére vagyunk kíváncsiak, ha nem, akkor, ha az egy path értékre mutat, akkor az ott tárolt egy darab adatot mutatja meg, ha kulcsra, akkor az alkulcsokat és az összes értéket megmutatja. Gyakorlatilag nagyon hasonlóan, ahogy a Get-ChildItem is működik. Fontos, hogy a kimeneten az adott elem neve mellett látjuk a pontos típusát is, és az értékek esetén az adatot is:
[2] PS C:\> Get-Registry HKCU:\SoosTibor
Name Type Value
---- ---- -----
(default) String Valami
Kifejtődő ExpandString %username%
Többsoros MultiString {Első, Második, Harmadik}
uj DWord 1
A fenti példában egy kulcsot listáztam, az alábbiban pedig ennek csak az alapértékét (backslash-re végződik a megadott paraméter!):
[3] PS C:\> Get-Registry HKCU:\SoosTibor\
Name Type Value
---- ---- -----
(default) String Valami
Ha pedig ki akarjuk fejteni a kifejtős szövegeket:
[4] PS C:\> Get-Registry HKCU:\SoosTibor\Kifejtődő -Expand
Name Type Value
---- ---- -----
Kifejtődő ExpandString soost
Még lehetne fejleszteni a kimenet formázásán egyedi nézetek definiálásával, de ezt már a tisztelt olvasóra bízom.
A teljesség kedvéért megemlítem, hogy a registry értékek típusait az alábbi RegistryValueKind felsorolástípusból is ki tudjuk olvasni, ha valakinek erre lenne szüksége:
[5] PS C:\> [Microsoft.Win32.RegistryValueKind] | gm -MemberType Properties -St
atic
TypeName: Microsoft.Win32.RegistryValueKind
Name MemberType Definition
---- ---------- ----------
Binary Property static Microsoft.Win32.RegistryValueKind Binary {get;}
DWord Property static Microsoft.Win32.RegistryValueKind DWord {get;}
ExpandString Property static Microsoft.Win32.RegistryValueKind ExpandStri...
MultiString Property static Microsoft.Win32.RegistryValueKind MultiStrin...
QWord Property static Microsoft.Win32.RegistryValueKind QWord {get;}
String Property static Microsoft.Win32.RegistryValueKind String {get;}
Unknown Property static Microsoft.Win32.RegistryValueKind Unknown {g...