Prihláste sa s kontom Microsoft
Prihláste sa alebo si vytvorte konto.
Dobrý deň,
Vyberte iné konto.
Máte viacero kont
Vyberte konto, s ktorým sa chcete prihlásiť.

Úvod

Spoločnosť Microsoft vyvinula vzorový skript prostredia PowerShell, ktorý vám pomôže automatizovať aktualizáciu prostredia Windows Recovery Environment (WinRE) v nasadených zariadeniach na riešenie chýb zabezpečenia v cve-2022-41099.

Vzorový skript prostredia PowerShell

Vzorový skript prostredia PowerShell vyvinul produktový tím spoločnosti Microsoft s cieľom automatizovať aktualizáciu obrázkov WinRE v Windows 10 a Windows 11 zariadeniach. Spustite skript s povereniami správcu v prostredí PowerShell v dotknutých zariadeniach. K dispozícii sú dva skripty – skript, ktorý by ste mali použiť, závisí od verzie Windowsu, ktorú používate. Použite príslušnú verziu pre svoje prostredie.

PatchWinREScript_2004plus.ps1 (odporúča sa)

Tento skript je určený pre Windows 10 verzie 2004 a novšie verzie vrátane Windows 11. Odporúčame používať túto verziu skriptu, pretože je robustnejší, ale používa funkcie dostupné len v Windows 10, verzii 2004 a novších verziách.

################################################################################################

#

# Copyright (c) Microsoft Corporation.

# Licensed under the MIT License.

#

# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE

# SOFTWARE.

#

################################################################################################

Param (

[Parameter(HelpMessage="Work Directory for patch WinRE")][string]$workDir="",

[Parameter(Mandatory=$true,HelpMessage="Path of target package")][string]$packagePath

)

# ------------------------------------

# Help functions

# ------------------------------------

# Log message

function LogMessage([string]$message)

{

$message = "$([DateTime]::Now) - $message"

Write-Host $message

}

function IsTPMBasedProtector

{

$DriveLetter = $env:SystemDrive

LogMessage("Checking BitLocker status")

$BitLocker = Get-WmiObject -Namespace "Root\cimv2\Security\MicrosoftVolumeEncryption" -Class "Win32_EncryptableVolume" -Filter "DriveLetter = '$DriveLetter'"

if(-not $BitLocker)

{

LogMessage("No BitLocker object")

return $False

}

$protectionEnabled = $False

switch ($BitLocker.GetProtectionStatus().protectionStatus){

("0"){

LogMessage("Unprotected")

break

}

("1"){

LogMessage("Protected")

$protectionEnabled = $True

break

}

("2"){

LogMessage("Uknown")

break

}

default{

LogMessage("NoReturn")

break

}

}

if (!$protectionEnabled)

{

LogMessage("Bitlocker isn’t enabled on the OS")

return $False

}

$ProtectorIds = $BitLocker.GetKeyProtectors("0").volumekeyprotectorID

$return = $False

foreach ($ProtectorID in $ProtectorIds){

$KeyProtectorType = $BitLocker.GetKeyProtectorType($ProtectorID).KeyProtectorType

switch($KeyProtectorType){

"1"{

LogMessage("Trusted Platform Module (TPM)")

$return = $True

break

}

"4"{

LogMessage("TPM And PIN")

$return = $True

break

}

"5"{

LogMessage("TPM And Startup Key")

$return = $True

break

}

"6"{

LogMessage("TPM And PIN And Startup Key")

$return = $True

break

}

default {break}

}#endSwitch

}#EndForeach

if ($return)

{

LogMessage("Has TPM-based protector")

}

else

{

LogMessage("Doesn't have TPM-based protector")

}

return $return

}

function SetRegistrykeyForSuccess

{

reg add HKLM\SOFTWARE\Microsoft\PushButtonReset /v WinREPathScriptSucceed /d 1 /f

}

function TargetfileVersionExam([string]$mountDir)

{

# Exam target binary

$targetBinary=$mountDir + "\Windows\System32\bootmenuux.dll"

LogMessage("TargetFile: " + $targetBinary)

$realNTVersion = [Diagnostics.FileVersionInfo]::GetVersionInfo($targetBinary).ProductVersion

$versionString = "$($realNTVersion.Split('.')[0]).$($realNTVersion.Split('.')[1])"

$fileVersion = $($realNTVersion.Split('.')[2])

$fileRevision = $($realNTVersion.Split('.')[3])

LogMessage("Target file version: " + $realNTVersion)

if (!($versionString -eq "10.0"))

{

LogMessage("Not Windows 10 or later")

return $False

}

$hasUpdated = $False

#Windows 10, version 1507 10240.19567

#Windows 10, version 1607 14393.5499

#Windows 10, version 1809 17763.3646

#Windows 10, version 2004 1904X.2247

#Windows 11, version 21H2 22000.1215

#Windows 11, version 22H2 22621.815

switch ($fileVersion) {

"10240" {

LogMessage("Windows 10, version 1507")

if ($fileRevision -ge 19567)

{

LogMessage("Windows 10, version 1507 with revision " + $fileRevision + " >= 19567, updates have been applied")

$hasUpdated = $True

}

break

}

"14393" {

LogMessage("Windows 10, version 1607")

if ($fileRevision -ge 5499)

{

LogMessage("Windows 10, version 1607 with revision " + $fileRevision + " >= 5499, updates have been applied")

$hasUpdated = $True

}

break

}

"17763" {

LogMessage("Windows 10, version 1809")

if ($fileRevision -ge 3646)

{

LogMessage("Windows 10, version 1809 with revision " + $fileRevision + " >= 3646, updates have been applied")

$hasUpdated = $True

}

break

}

"19041" {

LogMessage("Windows 10, version 2004")

if ($fileRevision -ge 2247)

{

LogMessage("Windows 10, version 2004 with revision " + $fileRevision + " >= 2247, updates have been applied")

$hasUpdated = $True

}

break

}

"22000" {

LogMessage("Windows 11, version 21H2")

if ($fileRevision -ge 1215)

{

LogMessage("Windows 11, version 21H2 with revision " + $fileRevision + " >= 1215, updates have been applied")

$hasUpdated = $True

}

break

}

"22621" {

LogMessage("Windows 11, version 22H2")

if ($fileRevision -ge 815)

{

LogMessage("Windows 11, version 22H2 with revision " + $fileRevision + " >= 815, updates have been applied")

$hasUpdated = $True

}

break

}

default {

LogMessage("Warning: unsupported OS version")

}

}

return $hasUpdated

}

function PatchPackage([string]$mountDir, [string]$packagePath)

{

# Exam target binary

$hasUpdated =TargetfileVersionExam($mountDir)

if ($hasUpdated)

{

LogMessage("The update has already been added to WinRE")

SetRegistrykeyForSuccess

return $False

}

# Add package

LogMessage("Apply package:" + $packagePath)

Dism /Add-Package /Image:$mountDir /PackagePath:$packagePath

if ($LASTEXITCODE -eq 0)

{

LogMessage("Successfully applied the package")

}

else

{

LogMessage("Applying the package failed with exit code: " + $LASTEXITCODE)

return $False

}

# Cleanup recovery image

LogMessage("Cleanup image")

Dism /image:$mountDir /cleanup-image /StartComponentCleanup /ResetBase

if ($LASTEXITCODE -eq 0)

{

LogMessage("Cleanup image succeed")

}

else

{

LogMessage("Cleanup image failed: " + $LASTEXITCODE)

return $False

}

return $True

}

# ------------------------------------

# Execution starts

# ------------------------------------

# Check breadcrumb

if (Test-Path HKLM:\Software\Microsoft\PushButtonReset)

{

$values = Get-ItemProperty -Path HKLM:\Software\Microsoft\PushButtonReset

if (!(-not $values))

{

if (Get-Member -InputObject $values -Name WinREPathScriptSucceed)

{

$value = Get-ItemProperty -Path HKLM:\Software\Microsoft\PushButtonReset -Name WinREPathScriptSucceed

if ($value.WinREPathScriptSucceed -eq 1)

{

LogMessage("This script was previously run successfully")

exit 1

}

}

}

}

if ([string]::IsNullorEmpty($workDir))

{

LogMessage("No input for mount directory")

LogMessage("Use default path from temporary directory")

$workDir = [System.IO.Path]::GetTempPath()

}

LogMessage("Working Dir: " + $workDir)

$name = "CA551926-299B-27A55276EC22_Mount"

$mountDir = Join-Path $workDir $name

LogMessage("MountDir: " + $mountdir)

# Delete existing mount directory

if (Test-Path $mountDir)

{

LogMessage("Mount directory: " + $mountDir + " already exists")

LogMessage("Try to unmount it")

Dism /unmount-image /mountDir:$mountDir /discard

if (!($LASTEXITCODE -eq 0))

{

LogMessage("Warning: unmount failed: " + $LASTEXITCODE)

}

LogMessage("Delete existing mount direcotry " + $mountDir)

Remove-Item $mountDir -Recurse

}

# Create mount directory

LogMessage("Create mount directory " + $mountDir)

New-Item -Path $mountDir -ItemType Directory

# Set ACL for mount directory

LogMessage("Set ACL for mount directory")

icacls $mountDir /inheritance:r

icacls $mountDir /grant:r SYSTEM:"(OI)(CI)(F)"

icacls $mountDir /grant:r *S-1-5-32-544:"(OI)(CI)(F)"

# Mount WinRE

LogMessage("Mount WinRE:")

reagentc /mountre /path $mountdir

if ($LASTEXITCODE -eq 0)

{

# Patch WinRE

if (PatchPackage -mountDir $mountDir -packagePath $packagePath)

{

$hasUpdated = TargetfileVersionExam($mountDir)

if ($hasUpdated)

{

LogMessage("After patch, find expected version for target file")

}

else

{

LogMessage("Warning: After applying the patch, unexpected version found for the target file")

}

LogMessage("Patch succeed, unmount to commit change")

Dism /unmount-image /mountDir:$mountDir /commit

if (!($LASTEXITCODE -eq 0))

{

LogMessage("Unmount failed: " + $LASTEXITCODE)

exit 1

}

else

{

if ($hasUpdated)

{

if (IsTPMBasedProtector)

{

# Disable WinRE and re-enable it to let new WinRE be trusted by BitLocker

LogMessage("Disable WinRE")

reagentc /disable

LogMessage("Re-enable WinRE")

reagentc /enable

reagentc /info

}

# Leave a breadcrumb indicates the script has succeed

SetRegistrykeyForSuccess

}

}

}

else

{

LogMessage("Patch failed or is not applicable, discard unmount")

Dism /unmount-image /mountDir:$mountDir /discard

if (!($LASTEXITCODE -eq 0))

{

LogMessage("Unmount failed: " + $LASTEXITCODE)

exit 1

}

}

}

else

{

LogMessage("Mount failed: " + $LASTEXITCODE)

}

# Cleanup Mount directory in the end

LogMessage("Delete mount direcotry")

Remove-Item $mountDir -Recurse

PatchWinREScript_General.ps1

Tento skript je určený pre Windows 10, verziu 1909 a staršie verzie, ale vykonáva sa vo všetkých verziách Windows 10 a Windows 11.

################################################################################################

#

# Copyright (c) Microsoft Corporation.

# Licensed under the MIT License.

#

# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE

# SOFTWARE.

#

################################################################################################

Param (

[Parameter(HelpMessage="Work Directory for patch WinRE")][string]$workDir="",

[Parameter(Mandatory=$true,HelpMessage="Path of target package")][string]$packagePath

)

# ------------------------------------

# Help functions

# ------------------------------------

# Log message

function LogMessage([string]$message)

{

$message = "$([DateTime]::Now) - $message"

Write-Host $message

}

function IsTPMBasedProtector

{

$DriveLetter = $env:SystemDrive

LogMessage("Checking BitLocker status")

$BitLocker = Get-WmiObject -Namespace "Root\cimv2\Security\MicrosoftVolumeEncryption" -Class "Win32_EncryptableVolume" -Filter "DriveLetter = '$DriveLetter'"

if(-not $BitLocker)

{

LogMessage("No BitLocker object")

return $False

}

$protectionEnabled = $False

switch ($BitLocker.GetProtectionStatus().protectionStatus){

("0"){

LogMessage("Unprotected")

break

}

("1"){

LogMessage("Protected")

$protectionEnabled = $True

break

}

("2"){

LogMessage("Uknown")

break

}

default{

LogMessage("NoReturn")

break

}

}

if (!$protectionEnabled)

{

LogMessage("Bitlocker isn’t enabled on the OS")

return $False

}

$ProtectorIds = $BitLocker.GetKeyProtectors("0").volumekeyprotectorID

$return = $False

foreach ($ProtectorID in $ProtectorIds){

$KeyProtectorType = $BitLocker.GetKeyProtectorType($ProtectorID).KeyProtectorType

switch($KeyProtectorType){

"1"{

LogMessage("Trusted Platform Module (TPM)")

$return = $True

break

}

"4"{

LogMessage("TPM And PIN")

$return = $True

break

}

"5"{

LogMessage("TPM And Startup Key")

$return = $True

break

}

"6"{

LogMessage("TPM And PIN And Startup Key")

$return = $True

break

}

default {break}

}#endSwitch

}#EndForeach

if ($return)

{

LogMessage("Has TPM-based protector")

}

else

{

LogMessage("Doesn't have TPM-based protector")

}

return $return

}

function SetRegistrykeyForSuccess

{

reg add HKLM\SOFTWARE\Microsoft\PushButtonReset /v WinREPathScriptSucceed /d 1 /f

}

function TargetfileVersionExam([string]$mountDir)

{

# Exam target binary

$targetBinary=$mountDir + "\Windows\System32\bootmenuux.dll"

LogMessage("TargetFile: " + $targetBinary)

$realNTVersion = [Diagnostics.FileVersionInfo]::GetVersionInfo($targetBinary).ProductVersion

$versionString = "$($realNTVersion.Split('.')[0]).$($realNTVersion.Split('.')[1])"

$fileVersion = $($realNTVersion.Split('.')[2])

$fileRevision = $($realNTVersion.Split('.')[3])

LogMessage("Target file version: " + $realNTVersion)

if (!($versionString -eq "10.0"))

{

LogMessage("Not Windows 10 or later")

return $False

}

$hasUpdated = $False

#Windows 10, version 1507 10240.19567

#Windows 10, version 1607 14393.5499

#Windows 10, version 1809 17763.3646

#Windows 10, version 2004 1904X.2247

#Windows 11, version 21H2 22000.1215

#Windows 11, version 22H2 22621.815

switch ($fileVersion) {

"10240" {

LogMessage("Windows 10, version 1507")

if ($fileRevision -ge 19567)

{

LogMessage("Windows 10, version 1507 with revision " + $fileRevision + " >= 19567, updates have been applied")

$hasUpdated = $True

}

break

}

"14393" {

LogMessage("Windows 10, version 1607")

if ($fileRevision -ge 5499)

{

LogMessage("Windows 10, version 1607 with revision " + $fileRevision + " >= 5499, updates have been applied")

$hasUpdated = $True

}

break

}

"17763" {

LogMessage("Windows 10, version 1809")

if ($fileRevision -ge 3646)

{

LogMessage("Windows 10, version 1809 with revision " + $fileRevision + " >= 3646, updates have been applied")

$hasUpdated = $True

}

break

}

"19041" {

LogMessage("Windows 10, version 2004")

if ($fileRevision -ge 2247)

{

LogMessage("Windows 10, version 2004 with revision " + $fileRevision + " >= 2247, updates have been applied")

$hasUpdated = $True

}

break

}

"22000" {

LogMessage("Windows 11, version 21H2")

if ($fileRevision -ge 1215)

{

LogMessage("Windows 11, version 21H2 with revision " + $fileRevision + " >= 1215, updates have been applied")

$hasUpdated = $True

}

break

}

"22621" {

LogMessage("Windows 11, version 22H2")

if ($fileRevision -ge 815)

{

LogMessage("Windows 11, version 22H2 with revision " + $fileRevision + " >= 815, updates have been applied")

$hasUpdated = $True

}

break

}

default {

LogMessage("Warning: unsupported OS version")

}

}

return $hasUpdated

}

function PatchPackage([string]$mountDir, [string]$packagePath)

{

# Exam target binary

$hasUpdated = TargetfileVersionExam($mountDir)

if ($hasUpdated)

{

LogMessage("The update has already been added to WinRE")

SetRegistrykeyForSuccess

return $False

}

# Add package

LogMessage("Apply package:" + $packagePath)

Dism /Add-Package /Image:$mountDir /PackagePath:$packagePath

if ($LASTEXITCODE -eq 0)

{

LogMessage("Successfully applied the package")

}

else

{

LogMessage("Applying the package failed with exit code: " + $LASTEXITCODE)

return $False

}

# Cleanup recovery image

LogMessage("Cleanup image")

Dism /image:$mountDir /cleanup-image /StartComponentCleanup /ResetBase

if ($LASTEXITCODE -eq 0)

{

LogMessage("Cleanup image succeed")

}

else

{

LogMessage("Cleanup image failed: " + $LASTEXITCODE)

return $False

}

return $True

}

# ------------------------------------

# Execution starts

# ------------------------------------

# Check breadcrumb

if (Test-Path HKLM:\Software\Microsoft\PushButtonReset)

{

$values = Get-ItemProperty -Path HKLM:\Software\Microsoft\PushButtonReset

if (!(-not $values))

{

if (Get-Member -InputObject $values -Name WinREPathScriptSucceed)

{

$value = Get-ItemProperty -Path HKLM:\Software\Microsoft\PushButtonReset -Name WinREPathScriptSucceed

if ($value.WinREPathScriptSucceed -eq 1)

{

LogMessage("This script was previously run successfully")

exit 1

}

}

}

}

# Get WinRE info

$WinREInfo = Reagentc /info

$findLocation = $False

foreach ($line in $WinREInfo)

{

$params = $line.Split(':')

if ($params.count -le 1)

{

continue

}

if ($params[1].Lenght -eq 0)

{

continue

}

$content = $params[1].Trim()

if ($content.Lenght -eq 0)

{

continue

}

$index = $content.IndexOf("\\?\")

if ($index -ge 0)

{

LogMessage("Find \\?\ at " + $index + " for [" + $content + "]")

$WinRELocation = $content

$findLocation = $True

}

}

if (!$findLocation)

{

LogMessage("WinRE Disabled")

exit 1

}

LogMessage("WinRE Enabled. WinRE location:" + $WinRELocation)

$WinREFile = $WinRELocation + "\winre.wim"

if ([string]::IsNullorEmpty($workDir))

{

LogMessage("No input for mount directory")

LogMessage("Use default path from temporary directory")

$workDir = [System.IO.Path]::GetTempPath()

}

LogMessage("Working Dir: " + $workDir)

$name = "CA551926-299B-27A55276EC22_Mount"

$mountDir = Join-Path $workDir $name

LogMessage("MountDir: " + $mountdir)

# Delete existing mount directory

if (Test-Path $mountDir)

{

LogMessage("Mount directory: " + $mountDir + " already exists")

LogMessage("Try to unmount it")

Dism /unmount-image /mountDir:$mountDir /discard

if (!($LASTEXITCODE -eq 0))

{

LogMessage("Warning: unmount failed: " + $LASTEXITCODE)

}

LogMessage("Delete existing mount direcotry " + $mountDir)

Remove-Item $mountDir -Recurse

}

# Create mount directory

LogMessage("Create mount directory " + $mountDir)

New-Item -Path $mountDir -ItemType Directory

# Set ACL for mount directory

LogMessage("Set ACL for mount directory")

icacls $mountDir /inheritance:r

icacls $mountDir /grant:r SYSTEM:"(OI)(CI)(F)"

icacls $mountDir /grant:r *S-1-5-32-544:"(OI)(CI)(F)"

# Mount WinRE

LogMessage("Mount WinRE:")

Dism /mount-image /imagefile:$WinREFile /index:1 /mountdir:$mountDir

if ($LASTEXITCODE -eq 0)

{

# Patch WinRE

if (PatchPackage -mountDir $mountDir -packagePath $packagePath)

{

$hasUpdated = TargetfileVersionExam($mountDir)

if ($hasUpdated)

{

LogMessage("After patch, find expected version for target file")

}

else

{

LogMessage("Warning: After applying the patch, unexpected version found for the target file")

}

LogMessage("Patch succeed, unmount to commit change")

Dism /unmount-image /mountDir:$mountDir /commit

if (!($LASTEXITCODE -eq 0))

{

LogMessage("Unmount failed: " + $LASTEXITCODE)

exit 1

}

else

{

if ($hasUpdated)

{

if (IsTPMBasedProtector)

{

# Disable WinRE and re-enable it to let new WinRE be trusted by BitLocker

LogMessage("Disable WinRE")

reagentc /disable

LogMessage("Re-enable WinRE")

reagentc /enable

reagentc /info

}

# Leave a breadcrumb indicates the script has succeed

SetRegistrykeyForSuccess

}

}

}

else

{

LogMessage("Patch failed or is not applicable, discard unmount")

Dism /unmount-image /mountDir:$mountDir /discard

if (!($LASTEXITCODE -eq 0))

{

LogMessage("Unmount failed: " + $LASTEXITCODE)

exit 1

}

}

}

else

{

LogMessage("Mount failed: " + $LASTEXITCODE)

}

# Cleanup Mount directory in the end

LogMessage("Delete mount direcotry")

Remove-Item $mountDir -Recurse

Ďalšie informácie

Keď sa zariadenie spustilo do spustenej verzie Windowsu nainštalovanej v zariadení, skript vykoná tieto kroky:

  1. Pripojte existujúci obrázok WinRE (WINRE). WIM).

  2. Aktualizujte obrázok WinRE pomocou zadaného balíka bezpečnej dynamickej aktualizácie OS (aktualizácia kompatibility), ktorý je k dispozícii v katalógu Windows Update. Odporúčame používať najnovšiu dynamickú aktualizáciu bezpečného operačného systému, ktorá je k dispozícii pre verziu Windowsu nainštalovanú v zariadení.

  3. Odpojte obrázok WinRE.

  4. Ak je k dispozícii protektor TPM pre šifrovanie BitLocker, znova nakonfiguruje WinRE pre službu BitLocker.

    Dôležité Tento krok nie je prítomný vo väčšine skriptov tretích strán na použitie aktualizácií na obrázok WinRE.

Spotreba

Do skriptu je možné odovzdať nasledujúce parametre:

Parameter

Popis

workDir

<voliteľné> Určuje scratch space used to patch WinRE. Ak nie je zadaný, skript použije predvolený dočasný priečinok pre zariadenie.

packagePath

<požadované> Určuje cestu a názov balíka aktualizácie Safe OS Dynamic špecifického pre verziu operačného systému a procesora, ktorý sa použije na aktualizáciu obrázka WinRE.

Poznámka Môže to byť lokálna cesta alebo vzdialená cesta UNC, ale dynamická aktualizácia zabezpečeného operačného systému sa musí stiahnuť a je k dispozícii na použitie skriptu.

Príklad: 

.\PatchWinREScript_2004plus.ps1 -packagePath "\\server\share\windows10.0-kb5021043-x64_efa19d2d431c5e782a59daaf2d.cab

Referencie

Ako písať a spúšťať skripty v Windows PowerShell ISE 

Potrebujete ďalšiu pomoc?

Chcete ďalšie možnosti?

Môžete preskúmať výhody predplatného, prehľadávať školiace kurzy, naučiť sa zabezpečiť svoje zariadenie a ešte oveľa viac.

Komunity pomôžu s kladením otázok a odpovedaním na ne, s poskytovaním pripomienok a so získavaním informácií od odborníkov s bohatými znalosťami.

Boli tieto informácie užitočné?

Aká je podľa vás jazyková kvalita textu?
Čo sa vám páčilo, prípadne čo nie?
Stlačením tlačidla Odoslať sa vaše pripomienky použijú na zlepšenie produktov a služieb spoločnosti Microsoft. Váš správca IT bude môcť tieto údaje zhromažďovať. Vyhlásenie o ochrane osobných údajov.

Ďakujeme za vaše pripomienky!

×