Posted in: Základy PowerShellu

Podepisování kódu v PowerShellu

Dnes to bude trochu bezpečnostní téma i když jen tak na půl. Podepisování skriptů rozhodně souvisí s jejich validací a bezpečností. Pokud se někdo pokusí modifikovat podepsaný skript, podpis se stane neplatným a modifikovaný skript se nevykoná, což samo o sobě může působit bezpečně.

Problém je, že jde obcházet ExecutionPolicy, takže jde spustit i nepodepsaný skript a teoreticky i skript s nevalidním podpisem. Na druhou stranu se musí uznat, že je rozhodně bezpečnější skripty podepisovat a pro běh daný podpis vyžadovat, nežli se na to vykašlat, protože tím útočníkovi zvedáme cenu útoku.

Problémem je, kde vzít správný certifikát. Patřičný certifikát lze vystavit pomocí interní certifikační autority v podnikové síti, ale musí být správně nastaven a správně ošetřeno, komu a s jakou platností se certifikát vydává. V domácím prostředí to nelze důvěryhodně udělat.

Nyní již ke skriptu, který umí podepsat zvoleným certifikátem libovolný soubor.

Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert
$cert = Read-host -promt „Zadej Thumbprint podposového certifikátu“
$cesta = Read-Host -promt „Zadej cestu k souboru“
Set-AuthenticodeSignature -FilePath $cesta -Certificate (Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert | where Thumbprint -eq  $cert) -TimestampServer http://timestamp.comodoca.com

Časový server doporučuji zaměnit za interní, ale i takto s veřejnou certifikační autoritou půjde podepsat certifikátem od autority interní.

Posted in: Windows 10, Windows 11, Windows 8 a 8.1, Windows server

Přidání PC do domény pomocí PowerShellu

Někdy se může hodit naskriptovat si přidání PC do domény. Může se jednat o to, že tuto akci z nějakého důvodu, např. nasazení LAPS, budeme chtít provést jako poslední akci z MDT task sekvenci. Nejsnazší je pak tuto akci provést jako spuštění PowerShell skriptu, který bude využívat nějaký servisní účet k této akci určený.

Problematiku práce s heslem v PowerShellu nechám na jiné téma, přestavte si, že máme přihlašovací údaje uložené někde v registru instalačního serveru. V ukázce níže jsou údaje součástí kódu, což není z pohledu bezpečnosti správně, ale naplnění jednotlivých proměnných může být rozličným způsobem.

$u = "domena\mdt" 
$d = "domena.local"
$p = ConvertTo-SecureString "5EiCJnRrgNrdQC3ZyEZauWg4PGPtMoIM10GC6qF618esuNKVva" -Force
$c = New-Object System.Management.Automation.PSCredential $u, $p
Add-Computer -DomainName $d -Credential $c

Výše uvedený kód vyžaduje, aby PowerShell běžel ve Full Language mode. Proměnná $c opisuje, co se na pozadí stane, když zapíšeme:

$c = Get-Credential

Pokud využijeme konstrukci Get-Credential, tak se nám zobrazí okno pro zadání loginu a hesla.

Posted in: Základy PowerShellu

Operátory v PowerSellu

Operátory porovnání

OperátorVýznam
-eqrovnost
-nenerovnost
-ltmenší než
-lemenší nebo rovno
-gevětší nebo rovno
-gtvětší než

Další operátory níže v přehledu

Matematické operátory

OperátorVýznam
-eqrovnost
-nenerovnost
++inkrementace
dekrementace
-notnegace
%modulo
+součet (zřetězení pro texty)
rozdíl
/dělení
*násobení

Přehled operátorů

OperátorVýznamDetail
[]Ohraničení typuJakýkoli znak umístěný uvnitř těchto příloh se považuje za součást názvu doslovného typu. Obsah není vyhodnocen jako výraz.
” “Dvojité uvozovky řetězců 
‘ ‘Jednoduché uvozovky řetězců 
@” “@Přílohy s dvojitým uvozovkami 
@’ ‘@Přílohy s jednoduchými uvozovkami 
{}Script block 
()Vnořený výraz 
@()Pole subvýrazů či hodnot 
$()Subvýraz 
.Operátor přístupu k vlastnostem a funkcím 
::Operátor přístupu ke statickým vlastnostem 
[]Index operator 
[int]Operátor datového typuVíce sousedních operátorů v tomto řádku má vyhodnocení zprava doleva.
-split (unary)Operátor rozdělení (unární)Tyto operátory lze použít jako unární nebo binární operátory. Jejich přednost se liší v závislosti na tom, jak jsou použity.
-join (unary)Operátor sloučení (unary) 
,Oddělovač prvků poleTento operátor je oddělovač prvků pole. Může být použit jako unární nebo binární operátor.
++InkrementaceTyto unární operátory lze použít před nebo po proměnné nebo vlastnosti. Při použití před proměnnou nebo vlastností (jako operátor předpony) je hodnota nejprve zvýšena nebo snížena a výsledek je předán do výrazu, ve kterém je obsažen. Při použití za proměnnou nebo vlastností (jako operátor postfixu) je hodnota předána do výrazu, ve kterém je obsažena, a pak je proměnná nebo vlastnost okamžitě zvýšena nebo snížena.
– –Dekrementace 
NegaceMultiple adjacent operators in this row have a right-to-left evaluation.
-notNot operator 
!Not operator 
-bnotBitový not operator 
..Rozsah 
-fFormat operator 
*Násobení operator 
/Dělení operator 
%Modulo operator 
+Sčítání operator 
Odčítání operator 
-splitRozdělení operator (binary)S výjimkou operátora spojení a operátorů typu (-is, -isnot a –as) má každý z operátorů v tomto řádku variantu bez rozlišování velkých a malých písmen. Varianty citlivé na malá a velká písmena jsou předponovány písmenem c (např. -Ceq) a varianty citlivé na malá a velká písmena jsou předponou i (např. –Ireplace).
-isplit  
-csplit (binary)  
-join (binary)Sloučení operator (binary) 
-isType is operator 
-isnotType is not operator 
-asType as operator 
-eqRovná se 
-ieq  
-ceq  
-neNerovná se 
-ine  
-cne  
-gtVětší než 
-igt  
-cgt  
-geVětší rovno 
-ige  
-cge  
-ltMenší než 
-ilt  
-clt  
-leMenší rovno 
-ile  
-cle  
-likepodobný 
-ilike  
-clike  
-notlikenepodobný 
-inotlike  
-cnotlike  
-matchMatch operator 
-imatch  
-cmatch  
-notmatchNot match operator 
-inotmatch  
-cnotmatch  
-containsobsahuje 
-icontains  
-ccontains  
-notcontainsNeobsahuje operator 
-inotcontains  
-cnotcontains  
-replaceNahrazení operator 
-ireplace  
-creplace  
-bandBitový and operator 
-borBitový or operator 
-bxorBitový exclusive or operator 
-andLogický and operator 
-orLogický or operator 
-xorLogický exclusive or operator 
.Zpřístupnění proměnných a funkcí ze skriptů a modulůUnární operátory, které jsou platné pouze na začátku výrazu, vnořeného výrazu nebo subexprese.
&Volání spustitelného souboru či kódu 
=přiřazeníMultiple adjacent operators in this row have a right-to-left evaluation.
+=Přiřazení přičtením 
-=Přiřazení odečtením 
*=Přiřazení násobením 
/=Přiřazením dělením 
%=Přiřazení modulem 
  • Na pole lze použít operátory sčítání s konstantou (přidá prvek do pole) a násobení konstantou (zduplikuje pole tolikrát, kolikrát uvádí konstanta)
Posted in: Windows server

Report nastavení všech GPO

Nejeden admin si především při přebírání prostředí kladl otázku, jak exportovat všechna GPO nastavení do čitelné podoby, aby se nemusel probírat jednotlivými objekty. Moje doporučení je, opravdu vzít si GPO konzoli a probírat se všemi jednotlivými objekty pro jednotlivá OU samostatně, ale cesta, jak vytvořit report obsahující vše je.

Běžný HTML report, stejný jako vrací gprusult /h lze ze všech GPO objektů vytvořit následujícím PowerShell příkazem:

Get-GPOReport -All -ReportType HTML -Path "D:\pom\AllGPOs.html" 

Cestu se ve výše uvedeném příkladu změňte dle libosti. Možná lepší je strojově čitelný formát XML, který by nám dokázal lépe filtrovat a prohledávat konfiguraci ve srovnání s HTML. XML report se pak vytvoří pomocí následujícího příkazu:

Get-GPOReport -All -ReportType Xml -Path "D:\pom\AllGPOs.xml" 

Pokud jde o strojově čitelný formát JSON, tak v něm už to tak přímočaré není, ale s trochou umu v PowerShellu jej jistě vytvoříte.

Posted in: Základy PowerShellu

Základní zabezpečení PowerShellu

Zabezpečení Powershellu začíná u zabezpečení operačního systému. Powershell je opravdu dvousečnou zbraní (nejlepším hackerským nástrojem i nejlepším přítelem obránců a správců), nicméně jsou určité postupy, které reálně snižují potenciální rizika spojená s přítomností PowerShellu. Nežli si dále povíme něco o zabezpečení PowerShellu jako takového, pojďme se podávat na základy. Doporučené body pro bezpečnou práci:

  1. Nepracuji pod účtem s admin oprávněním
  2. Nezpouštím pozornost z odemčeného PC
  3. Pravidleně instaluji bezpečnostní aktualizace
  4. Nespouštím skripty z internetu, které jsem celé nezkontroloval a nerozumím jim na 100%
  5. Moduly a další SW instaluji vždy z důvěryhodných zdrojů (oficiální stažení z webu vydavatele, ověření kontrolních součtů a vše pouze legálně)
  6. Všechny úlohy spouštím s minimálním nutným oprávněním
  7. Vždy mám na systému aktivní Firewall a zabezpečení
  8. Využívám komplexní hesla
  9. Dodržuji všechny bezpečnostní doporučení výrobce OS i jednotlivých aplikací
  10. Navštěvuji jen důvěryhodné weby a nic nedávám do výjimek bezpečnostních SW
  11. PowerShellu nedávám oprávnění administrátora, pokud není nezbytné
  12. S právy admina nespouštím skripty z internetu

Dalším doporučením je, aby práce vždy probíhala v aktuální verzi PowerShellu, verze 5.1 není problémem, pokud nechybí bezpečnostní aktualizace. Starší verze PowerShellu by měly být z PC odebrány, a pokud je potřebuje nějaký SW, mělo by být jejich spouštění logováno a omezeno na daný SW např. pomocí Applocker.

Execution Policy

V PowerShellu od verze 3 najdeme tzv. Execution Policy, což je nastavení, které říká, jaké skripty je povoleno spouštět. Jde o první obrannou linii PowerShellu. Ve výchozím stavu je na Windows Serveru hodnota RemoteSigned, na systémech Windows 10 je výchozí hodnotou Restricted. Co které nastavení znamená?

  • AllSigned Vyžaduje, aby všechny skripty a konfigurační soubory byly podepsány důvěryhodným vydavatelem, včetně skriptů napsaných v místním počítači.
  • Bypass Spustí jakýkoliv skript bez varování a výzev.
  • Default Nastaví na Windows serveru RemoteSigned a na Windows Restricted
  • RemoteSigned Všechny skripty a konfigurační soubory stažené z internetu musí být podepsány důvěryhodným vydavatelem.
  • Restricted Nenačte konfigurační soubory a nespustí skripty.
  • Undefined Pro obor nejsou nastaveny žádné zásady provádění. Odebere přiřazenou zásadu provádění z oboru, který není nastaven zásadami skupiny. Pokud je zásada provádění ve všech oborech Nedefinovaná, je účinná politika Restricted
  • Unrestricted Počínaje PowerShell 6.0 se jedná o výchozí zásadu provádění pro počítače, které nejsou Windows, a nelze ji změnit. Načte všechny konfigurační soubory a spustí všechny skripty. Pokud spustíte nepodepsaný skript, který byl stažen z internetu, budete před spuštěním vyzváni k povolení.

Jak zjistím aktuálně nastavenou politiku ve svém PowerShelu? Odpovědí je příkaz: 

Get-ExecutionPolicy -List

Jak nastavím Execution policy? Odpovědí je příkaz: 

Set-ExecutionPolicy

Execution policy jde nastavovat granuárně na různé úrovně. Pokud spustíme příkaz Set-ExecutionPolicy nastavujeme pravidla pouze pro daný proces PowerShellu. Pro nastavení pravidel například pro uživatele, počítač, nebo všechny uživatele složí přepínač: -Scope

Pro nastavení pravidel máme následující oblasti:

  • MachinePolicy Pomocí zásad skupiny aplikuje nastavení na všechny uživatele daného PC.
  • UserPolicy Nastavení platí lokálně pro daného uživatele.
  • Process Nastavení platí pouze pro dané okno PowerShellu.
  • CurrentUser Nastavení platí pouze pro daného uživatele (může s ním cestovat)
  • LocalMachine Mění výchozí nastavení pro všechny uživatele na daném PC.

Pokud nechcete, aby se v PowerShellu objevila výzva pro potvrzení nastavení použijte přepínač: -Force Pokud chci nastavit, že v aktuálně spuštěné instanci PowerShellu spustím podepsaný skript, využiji příklad níže.

Set-ExecutionPolicy AllSigned -Scope Process -Force

Obcházení Execution Policy

Obejít Execution Policy není nic těžkého a nejsou na to zapotřebí žádná oprávnění, člověk může být klidně uživatelem typu host. Níže si popíšeme 3 nejběžnější způsoby obcházení:

  1. Příkaz Set-ExecutionPolicy, kterým nastavím policy na požadovanou hodnotu (nelze provést uvnitř skriptu)
  2. V Průzkumníku kliknout na soubor skriptu pravým tlačítkem myši a zvolit „Run with PowerShell“
  3. Spustit si PowerShell ISE, skript v něm otevřít, celý označit pomocí CTRL+A a zvolit RUN SELECTION

Jak je vidět, tak Execution policy jsou pouze nástrojem, který má zabránit chybám z nepozornosti a nechtěnému spuštění kódu, nikoliv reálnou bezpečnostní technologií.

Constrained Language mode

Jak již bylo zmíněno PowerShell stojí na .NET Frameworku a z toho plyne, že umí volat .NET příkazy. Tato zkutečnost je podstatnou, protože dokáže zjednodušit některé úkony správy, ale zároveň je volání .NET příkazů alfou a omegou většiny škodlivých kódů v PowerShellu. Pro hackery je často samotný PowerShell skvělý pomocník, ale protože je určen pro jiné odvětví, je zároveň limitujícím faktorem útoku. Právě technologie Language mode, má za úkol omezit volání .NET příkazů, čímž eliminuje spouštění řady generických skriptů, které hackeři užívají.

Nastavení

Obrana proti školdivému kódu v PowerShellu je poměrně jednoduchá, stačí užívat Constrained Language mode, který značně omezí možnosti, které útočník má. Toto nastavení umožňuje zakázat volání .NET příkazů, a nastavit i další omezení omezení na vlastní PowerShell.

Zjištění jazykového režimu provedeme příkazem:

$ExecutionContext.SessionState.LanguageMode

Základní nastavení do omezeného režimu provedeme příkazem:

$ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"

Pokud toto nastavení provádíme příkazy, pak není možné jej z omezeného režimu vrátit zpět na plný režim v rámci stejného okna PowerShellu. Stejně jako u Execution policy zde nejsou zapotřebí žádná správcovská práva. Krom omezeného jazykového režimu existují i další, pojďme se tedy podívat na úplný výčet.

  • Full Language – Režim jazyka FullLanguage umožňuje všechny jazykové prvky v relaci. FullLanguage je výchozí jazykový režim
  • Restricted Language – V jazykovém režimu RestrictedLanguage mohou uživatelé používat příkazy (rutiny, funkce, příkazy CIM a pracovní postupy), ale není dovoleno používat bloky skriptů. Jsou omezeny i proměnné a operátory. Bližší informace: Get-Help about_Language_Modes
  • No Language – V jazykovém režimu NoLanguage mohou uživatelé spouštět příkazy, ale nemohou používat žádné jazykové prvky.
  • Constrained Language – povoluje všechny prvky jazyka PowerShell, ale neumožňuje volání .NET a vybraných systémových rutin.

Na rozdíl od Execution policy lze z pozice správce vynutit nastavení na úrovni počítače, jež pevně stavuje jazykový režim a uživatelé jej nemohou změnit. Toto pevné nastavení se provádí pomocí systémové proměnné __PSLockDownPolicy, což lze udělat příkazem .NET:

[Environment]::SetEnvironmentVariable('__PSLockdownPolicy', '4', 'Machine')

Další alternativou je využití systémového GIU:

Poslední možností, pro správce systémů tou nejlepší, je využití Group Policy, resp. Local Policy.

Blokované soubory z internetu

Soubory konfigurace, skriptů a nápovědy jsou ve výchozím stavu po stažení z internetu blokovány a PowerShell bude explicitně vyžadovat potvrzení, že má takový soubor opravdu spustit i když politiky spuštění povolují. Každý soubor, který je stažen z internetu má o této skutečnosti informující příznak v NTFS (alternativní datový proud Zone.Identifier, který má hodnotu „3“), proto PowerShell zná jeho původ. Tuto informaci neobsahují jen soubory pro PowerShell, ale také ostatní stažené soubory, jako jsou Office, PDF, MSI, EXE apod. Výjimku tvoří soubory stažené v rámci modulu příkazem Install-Module z PowerShell galerie nebo jiného důvěryhodného repozitáře, zde si je PowerShell v rámci procesu instalace odblokuje.

Pro odblokování souborů slouží příkaz Unblock-File, který má povinný parametr -Path, nicméně dokáže pracovat i s pozičním zadáním hodnoty parametru, tudíž bez uvedení jména parametru, jen zadáním jeho hodnoty.

Následující příkaz odblokuje všechny soubory umístěné v adresáři C:\Users\Public\Dokuments:

Get-ChildItem C:\Users\Public\Dokuments\*.* | Unblock-File

Výše zmíněný příkaz odblokuje všechny soubory, tedy i soubory Office, pdf či instalátory. Jeho užití tedy může leckdy ušetřit i klikání na Povolit úpravy v sadě Office na souborech stažených z Moodlu nebo SISu. Více o tomto příkazu v jeho dokumentaci.

Posted in: Základy PowerShellu

Exporty

PowerShell, respektive jeho moduly, umí opravdu rozličné množství exportů a výpisů, ale zde mi jde o export výstupu libovolného příkazu, nikoliv například certifikátu. Nejjednodušší možností je přesměrování konzole do souboru, což se provede příkazem out-file. Například seznam běžících procesů do souboru procesy.txt na ploše uložím takto:

get-process | Out-File $env:USERPROFILE\Desktop\procesy.txt

Lepší je využít export o nějakého dále zpracovatelného formátu, jako je CSV nebo XML.

Export do CSV

K exportu výstupu do CSV slouží příkaz Export-CSV, modifikací příkladu výše pro výstupní formát CSV je následující příkaz:

get-process | Export-Csv $env:USERPROFILE\Desktop\procesy.csv -Encoding UTF8 -Delimiter ";" -NoTypeInformation

Pojďme si to rozebrat. CSV jako výchozí oddělovač využívá čárku, ale v českém jazykovém prostředí se běžně využívá středník, aby se správně uložila desetinná čísla. Parametr Delimiter umí nastavit, právě znak, který je oddělovačem, pokud parametr nevyužijeme, bude SCV využívat čárku jako oddělovač. Dalším parametrem je Encoding, který udává, jaké kódování se užije, bez uvedení přebírá výchozí kódování OS, doporučuji využívat UFT-8, protože je dobře přenosné mezi aplikacemi i systémy. Posledním je důležitý parametr NoTypeInformation, který do výstupu nezapíše na první řádek informace o typu objektu (TypeName). Pokud tento parametr zapomeneme, na první řádek se zapíše typ objektu, v našem příkladu by to bylo: System.Diagnostics.Process Tento řádek pak ztěžuje zpracování souboru dále např. v Excelu, kdy musí být při importu odebrán. Kde naopak je dobré jej mít, je následné zpracování pomocí PowerShellu.

Export do XML

Zde je situace dost podobná jako v případě CSV. Náš příklad s procesy by vypadal následovně:

Get-Process | Export-Clixml -Path $env:USERPROFILE\Desktop\procesy.xml -Encoding Unicode

Export do JSON

Dnes velmi populární datový formát JSON má rovněž v PowerShellu podporu. Bohužel zde není přímý příkaz exportu, ale postup je takový, že výstup se zkonvertuje pomocí příkazu ConvertTo-Json do objektu, který je vnitřně JSON a ten se uloží do souboru pomocí Out-File. Náš příklad s procesy by tedy vypadal následovně:

Get-Process | ConvertTo-Json | Out-File -FilePath $env:USERPROFILE\Desktop\procesy.json

Konverze do HTLM

Jedním z dobrý „exportů“ větších tabulek a dlouhých výpisů může být HTML, které je dobře čitelné po zobrazení v prohlížeči a rovněž prezentovatelné další lidem. I zde využíváme, podobně jako u JSON, konverzi a následné uložení do souboru. Pokud bychom využili samotné ConvertTo-HTML, dostaneme výstup, který je vidět na následujícím obrázku.

Náš příklad by pro uložení v podobě tabulky webové stránky vypadal následovně:

Get-Process | ConvertTo-Html | Out-File $env:USERPROFILE\Desktop\procesy.html

Možností pro ConvertTo je ještě o něco více a využívají se běžně uvnitř samotného kódu skriptů, ale již ne jako export v rozšířeném formátu. O těchto možnostech zase někdy jindy.

Posted in: Základy PowerShellu

Runas v PowerShellu

Určitě jste se octli v situaci, kdy je potřeba spustit něco jako jiný uživatel. V GUI je to jednoduché, stačí kontextové menu, ale má to háček, na PC se načte v minimální podobě profil daného uživatele, jak na to bez toho? Řešením je PowerShell nebo cmd, kdy v CMD místo proměnné zadáte username přímo do příkazu runas.

$ucet = Read-Host -promt "Zadej login"
Runas /noprofile /user:$ucet "powershell.exe"

Z PowerShellu pak už pod daným uživatelem spustíte cokoliv. Když bych chtěl napsat runas korektně PowerShellově, tak by to vypadalo takto:

Start-Process powershell.exe -Credential (Get-Credential) 

Nevýhodou zápisu výše je, že se chová jako GUI, tedy dojde k naštení minimální potřebné části profilu uživatele.

Posted in: Windows server

Export dat z AD pro tvorbu organizačního diagramu

Dne jen krátký příspěvek v podobě příkazu, který exportuje data připravená pro tvorbu diagramu pracovníků v organizaci pomocí Excelu.

$Path = Read-Host -promt "Zadej cestu k výstupnímu souboru"
Get-ADUser -Filter * -Properties *| Select name, @{n='Manager';e={(Get-ADUser $_.manager).name}}, title, department | Export-Csv $Path -NoTypeInformation -Encoding UTF8 -Force

Alternativa pro zpracování ve Visio:

Import-Module ImportExcel -Force
$Path = Read-Host -promt "Zadej cestu k výstupnímu souboru" 
Get-ADUser -Filter * -Properties *| Select name, @{n='Manager';e={(Get-ADUser $_.manager).name}}, title, department | Export-Excel -Path $Path -Force

Posted in: Základy PowerShellu

Formátování výstupu

Každý výpis v PowerShellu má své váchozí formátování, které je ve většině případů nejlepším pro správné zobrazní výstupu, ale i tak si jej někdy potřebujeme měnit.

Samostatnou částí je v tuto chvíli otevření výstupu v samostatném okně s možností filtrování, vyhledávání a řazení. Tuto možnost získáme příkazem Out-GridView, který umisťujeme za pípu (znak: | ) na konci příkazu. Příklad pro vypsání procesů:

Get-Process | Out-GridView
  1. Format-Table – naformátuje výstup jako tabulku do konzule
  2. Format-Custom – naformátuje dle uživatelem zadané definice
  3. Format-Hex
  4. Format-List – je asi nejčastějším formátem pro podrobné výpisy
  5. Format-SecureBootUEFI – nutné podrobně studovat dokumentaci
  6. Format-Wide – jednosloupcové zobrazení, které se tipicky v konzoli zalamuje na dva sloupce

Jako příklad si ude uveďme výpis procesu iexplorer.exe (aplikace Internet Explorer)

Další informace o formátování výstupu pak nalezneme v dokumentaci. Někdy se za formátování výstupu dá považovat i export např. do JSON, nebo XML, ale o tom, zase někdy příště.

Back to Top