<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title><![CDATA[Серый форум &mdash; PowerShell: пример вычисления хешей файла различными способами]]></title>
		<link>http://forum.script-coding.com/viewtopic.php?id=15087</link>
		<atom:link href="http://forum.script-coding.com/extern.php?action=feed&amp;tid=15087&amp;type=rss" rel="self" type="application/rss+xml" />
		<description><![CDATA[Недавние сообщения в теме «PowerShell: пример вычисления хешей файла различными способами».]]></description>
		<lastBuildDate>Sat, 07 Dec 2019 19:59:07 +0000</lastBuildDate>
		<generator>PunBB</generator>
		<item>
			<title><![CDATA[PowerShell: пример вычисления хешей файла различными способами]]></title>
			<link>http://forum.script-coding.com/viewtopic.php?pid=136781#p136781</link>
			<description><![CDATA[<p>С появлением в PowerShell 4.0 командлета Get-FileHash получение хеша файла не является проблемой, но когда я начал изучать PowerShell, на Висте, вроде, был ещё только .Net 2.0 со своим весьма скудным пространством имён и вычисление хеша разными способами казалось интересной задачей. Тогда и написал этот скрипт, стараясь следовать тогдашним правилам написания и оформления кода. В то время у меня все мои скрипты (не только PowerShell, но и WSH) подписывались (что, как потом оказалось, ломало нормальную работу сторонних скриптов) и я выбрал тот вариант оформления кода, который мог обеспечить получение информации по Get-Help для подписанного скрипта, то есть &quot;описание в начале&quot;. Скрипт, возможно, интересен с точки зрения решения задачи различными способами и влияния выбранного способа на скорость работы, но, конечно, сейчас это имеет, разве что, исторический интерес. Тем не менее привожу скрипт здесь, предварительно поправив синтаксические неточности в описании, возможно он кого-то заинтересует. Check-Hash.ps1:<br /></p><div class="codebox"><pre><code>
&lt;#.SYNOPSIS
Выводит либо проверяет MD5, SHA1, SHA256, SHA384, SHA512 хеши указанного файла.
.DESCRIPTION
Выводит либо проверяет MD5, SHA1, SHA256, SHA384, SHA512 хеши указанного файла.
.PARAMETER Path
Задает путь к файлу.
.PARAMETER MD5
Вычисляет и выводит MD5 хеш.
.PARAMETER SHA1
Вычисляет и выводит SHA1 хеш.
.PARAMETER SHA256
Вычисляет и выводит SHA256 хеш.
.PARAMETER SHA384
Вычисляет и выводит SHA384 хеш.
.PARAMETER SHA512
Вычисляет и выводит SHA512 хеш.
.PARAMETER Common
Вычисляет и выводит MD5 и SHA1 хеш. Если ни один параметр MD5, SHA1, SHA256, SHA384 или SHA512 не задан, считается, что задан параметр Common.
.PARAMETER All
Вычисляет и выводит MD5, SHA1, SHA256, SHA384 и SHA512 хеш.
.PARAMETER CheckMD5
Задает хеш MD5, который следует проверить на совпадение с вычисленным.
.PARAMETER CheckSHA1
Задает хеш SHA1, который следует проверить на совпадение с вычисленным.
.PARAMETER CheckSHA256
Задает хеш SHA256, который следует проверить на совпадение с вычисленным.
.PARAMETER CheckSHA384
Задает хеш SHA384, который следует проверить на совпадение с вычисленным.
.PARAMETER CheckSHA512
Задает хеш SHA512, который следует проверить на совпадение с вычисленным.
.PARAMETER Action
Задает действие, которое следует выполнить. Допустимые значения: &quot;ComputeMD5&quot;, &quot;ComputeSHA1&quot;, &quot;ComputeSHA256&quot;, &quot;ComputeSHA384&quot;, &quot;ComputeSHA512&quot;, &quot;MD5&quot;, &quot;SHA1&quot;, &quot;SHA256&quot;, &quot;SHA384&quot;, &quot;SHA512&quot; - для вычисления соответствующего хеша; &quot;CheckMD5&quot;, &quot;CheckSHA1&quot;, &quot;CheckSHA256&quot;, &quot;CheckSHA384&quot;, &quot;CheckSHA512&quot; - для проверки хеша, заданного параметром GivenHash. Регистр символов параметра Action значения не имеет.
.PARAMETER GivenHash
Задает хеш, который следует проверить на совпадение с вычисленным.
.PARAMETER Mode
Задает режим вычисления нескольких хешей. Допустимые значения: 0 (значение по умолчанию) - файл читается однократно, все суммы расчитываются по мере чтения файла; 1 - каждая из хеш сумм вычисляется последовательно, файл читается столько раз, сколько требуется вычислить хешей и обрабатывается как поток, а не читается частями (применяется по умолчанию, если тербуется вычислить только одну хеш сумму); 2 - расчет выполняется параллельно в фоновых заданиях PowerShell, каждое задание вычисляет один хеш и работает в режиме 1 (режим 2 не действует, если необходимо вычислить только одну хеш сумму).
.PARAMETER ScriptArguments
Задает хеш-таблицу, которая используется для передачи дополнительной информации (общие и некоторые необязательные параметры) из основного скрипта в фоновые задания. Ключи хеш-таблицы задают имена переменных скрипта, значения которых должны быть установлены равными значениям хеш-таблицы. Не все переменные могут быть изменены таким способом.
.PARAMETER ToLower
Выводит хеш суммы строчными буквами.
.INPUTS
System.String
Строку, содержащую путь к файлу, можно передать скрипту Check-Hash по конвейеру.
.OUTPUTS
System.Collections.Hashtable
Выводит хеш-таблицу, содержащую вычисленные хеш суммы для файла или логические значения, отражающие успешность проверки заданных хеш сумм.
.NOTES
1. Быстрое прерывание вычислений по Control-Break возможно только в режиме 0. Этот режим можно задать и при вычислении одного хеша.
2. Когда проверяются несколько хеш сумм, выходная хеш-таблица будет содержать значение Status равное $true, если все хеш суммы совпали и $false в противном случае.
3. В режиме 2 из заданных обших параметров в фоновые задания передаются только параметры Verbose, WarningActon, ErrorAction, а также соответствующие им привилегированные переменные, если их значения не равны значениям по умолчанию.
#&gt;

[CmdletBinding(DefaultParameterSetName=&#039;Compute&#039;)]
Param(	[parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
		[String][Alias(&quot;FullName&quot;)][ValidateNotNullOrEmpty()]$Path,
	[parameter(ParameterSetName=&#039;Compute&#039;)][Switch]$MD5,
	[parameter(ParameterSetName=&#039;Compute&#039;)][Switch]$SHA1,
	[parameter(ParameterSetName=&#039;Compute&#039;)][Switch]$SHA256,
	[parameter(ParameterSetName=&#039;Compute&#039;)][Switch]$SHA384,
	[parameter(ParameterSetName=&#039;Compute&#039;)][Switch]$SHA512,
	[parameter(ParameterSetName=&#039;Compute&#039;)][Switch]$Common,
	[parameter(ParameterSetName=&#039;Compute&#039;)][Switch]$All,
	[parameter(ParameterSetName=&#039;Check&#039;)][String][ValidateLength(32,32)][ValidatePattern(&#039;[0-9a-fA-F]{32}&#039;)]$CheckMD5,
	[parameter(ParameterSetName=&#039;Check&#039;)][String][ValidateLength(40,40)][ValidatePattern(&#039;[0-9a-fA-F]{40}&#039;)]$CheckSHA1,
	[parameter(ParameterSetName=&#039;Check&#039;)][String][ValidateLength(64,64)][ValidatePattern(&#039;[0-9a-fA-F]{64}&#039;)]$CheckSHA256,
	[parameter(ParameterSetName=&#039;Check&#039;)][String][ValidateLength(96,96)][ValidatePattern(&#039;[0-9a-fA-F]{96}&#039;)]$CheckSHA384,
	[parameter(ParameterSetName=&#039;Check&#039;)][String][ValidateLength(128,128)][ValidatePattern(&#039;[0-9a-fA-F]{128}&#039;)]$CheckSHA512,
	[parameter(ParameterSetName=&#039;Compute&#039;)][parameter(ParameterSetName=&#039;Check&#039;)]
		[Int][ValidateRange(0,2)][ValidateScript({$script:ModeSet = $true; $true})]$Mode=0,
	[parameter(ParameterSetName=&#039;SingleSum&#039;, Mandatory=$true, Position=1)]
		[String][ValidatePattern(&#039;^(Check|Compute)?(MD5|SHA1|SHA256|SHA384|SHA512){1}$&#039;)]$Action,
	[parameter(ParameterSetName=&#039;SingleSum&#039;, Position=2)][String]$GivenHash,
	[parameter(ParameterSetName=&#039;SingleSum&#039;)][Hashtable]$ScriptArguments,
	[Switch]$ToLower)

function OutHashTable($out){
	if($out){$HashTable = @{}
		foreach($i in $out){$HashTable += @{([Array]$i.Keys)[0]=([Array]$i.Values)[0]}}
		if(($v = [Array]$HashTable.Values)[0] -is [Boolean] -and $v.length -gt 1){
			$Status = $true
			foreach($i in $v){if(!$i){$Status = $false; break}}
			$HashTable += @{Status=$Status}
		}
	}
	$HashTable
}

function GetTypes($a){$t=@(); foreach($i in $a){$t += @($i.type)}; $t -join &#039;, &#039;}

$Path = Resolve-Path $Path
if(!(Test-Path $Path)){Throw &quot;Не найден:&quot;&quot;$Path&quot;&quot;&quot;}
$a = @()
switch($PsCmdlet.ParameterSetName){
	&#039;Check&#039;{
		if($CheckMD5){$a += @{type=&#039;MD5&#039;; value=$CheckMD5}}
		if($CheckSHA1){$a += @{type=&#039;SHA1&#039;; value=$CheckSHA1}}
		if($CheckSHA256){$a += @{type=&#039;SHA256&#039;; value=$CheckSHA256}}
		if($CheckSHA384){$a += @{type=&#039;SHA384&#039;; value=$CheckSHA384}}
		if($CheckSHA512){$a += @{type=&#039;SHA512&#039;; value=$CheckSHA512}}
	}
	&#039;Compute&#039;{
		if($MD5 -or $Common -or $All){$a += @{type=&#039;MD5&#039;}}
		if($SHA1 -or $Common -or $All){$a += @{type=&#039;SHA1&#039;}}
		if($SHA256 -or $All){$a += @{type=&#039;SHA256&#039;}}
		if($SHA384 -or $All){$a += @{type=&#039;SHA384&#039;}}
		if($SHA512 -or $All){$a += @{type=&#039;SHA512&#039;}}
	}
	&#039;SingleSum&#039;{
		if(($Action -notmatch &#039;Check&#039; -and !$GivenHash) -or ($Action -match &#039;Check&#039; -and`
		(($Action -match &#039;MD5&#039; -and $GivenHash -match &#039;[0-9a-fA-F]{32}&#039;) -or`
		($Action -match &#039;SHA1&#039; -and $GivenHash -match &#039;[0-9a-fA-F]{40}&#039;) -or`
		($Action -match &#039;SHA256&#039; -and $GivenHash -match &#039;[0-9a-fA-F]{64}&#039;) -or`
		($Action -match &#039;SHA384&#039; -and $GivenHash -match &#039;[0-9a-fA-F]{96}&#039;) -or`
		($Action -match &#039;SHA512&#039; -and $GivenHash -match &#039;[0-9a-fA-F]{128}&#039;)))){
			$h = @{type=$Action -replace &#039;Check|Compute&#039;, &#039;&#039;}
			if($GivenHash){$h += @{value=$GivenHash}}
			$a += $h
		}else{Throw &quot;Значение параметра GivenHash задано неверно!&quot;}
		if($ScriptArguments){
			$ScriptArguments.GetEnumerator() | Foreach-Object {
				if(&#039;a&#039;, &#039;Path&#039;, &#039;value&#039;, &#039;out&#039; -notcontains $_.Key){
					if(&#039;Verbose&#039;, &#039;ErrorAction&#039; -contains $_.Key){
							$Key = &quot;$($_.Key)Preference&quot;
							$NewValue = if($_.Value -isnot [Boolean]){$_.Value}
								else{&quot;$(if(!$_.Value){&#039;Silently&#039;})Continue&quot;}
						}
						else{	$Key = &quot;$($_.Key)&quot;
							if($Key -eq &#039;WarningAction&#039;){$Key = &#039;WarningPreference&#039;}
							$NewValue = $_.Value
						}
					Set-Variable &quot;$Key&quot; -Value $NewValue -Scope Script
				}
			}
		}
	}
}
if(!$a.Count){$a = @(@{type=&#039;MD5&#039;}, @{type=&#039;SHA1&#039;})}
$Script = $MyInvocation.MyCommand.Path
$bufsize = 16kb
$buffer = New-Object Byte[] -ArgumentList $bufsize
if($a.Count -eq 1 -and (!$ModeSet -or ($ModeSet -and $Mode -gt 0))){
	$type = $a[0].type
	if($a[0].value){$value = $a[0].value}
	Write-Verbose &quot;Расчет $type выполняется в режиме 1&quot;
	$file = New-Object System.IO.FileStream($Path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read,
		[System.IO.FileShare]::Read, $bufsize)
	$CSP = New-Object &quot;System.Security.Cryptography.${type}CryptoServiceProvider&quot;
	if(!$ToLower){$type = $type.ToUpper(); $x = &#039;X2&#039;}else{$type = $type.ToLower(); $x = &#039;x2&#039;}
	$hash = ($CSP.ComputeHash($file) | ForEach-Object {$_.ToString($x)}) -join &#039;&#039;
	$file.Close()
	if($value){@{$type=$hash -eq $value}}else{@{$type=$hash}}
}elseif($Mode -eq 0){
	Write-Verbose &quot;Расчет $(GetTypes $a) выполняется в режиме 0&quot;
	$file = New-Object System.IO.FileStream($Path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read,
		[System.IO.FileShare]::Read, $bufsize)
	for($i = 0; $i -lt $a.length; $i++){
		$a[$i] += @{CSP=New-Object &quot;System.Security.Cryptography.$($a[$i].type)CryptoServiceProvider&quot;}
	}
	while($bytes = $file.Read($buffer, 0, $bufsize)){
		for($i = 0; $i -lt $a.length; $i++){[Void]$a[$i].CSP.TransformBlock($buffer, 0, $bytes, $buffer, 0)}
	}
	for($i = 0; $i -lt $a.length; $i++){[Void]$a[$i].CSP.TransformFinalBlock($buffer, 0, 0)}
	$file.Close()
	$out = @()
	if(!$ToLower){$x = &#039;X2&#039;}else{$x = &#039;x2&#039;}
	for($i = 0; $i -lt $a.length; $i++){
		$hash = ($a[$i].CSP.Hash | ForEach-Object {$_.ToString($x)}) -join &#039;&#039;
		$type = if(!$ToLower){$a[$i].type.ToUpper()}else{$a[$i].type.ToLower()}
		$out += if($a[$i].value){@{$type=$hash -eq $a[$i].value}}else{@{$type=$hash}}
	}	
	OutHashTable $out
}elseif($Mode -eq 1){
	Write-Verbose &quot;Расчет $(GetTypes $a) выполняется в режиме 1&quot;
	$out = @()
	foreach($i in $a){
		$out += &amp; &quot;$Script&quot; $Path &quot;$(if($i.value){&quot;Check&quot;})$($i.type)&quot; &quot;$(if($i.value){$i.value})&quot; -ToLower:$ToLower
	}
	OutHashTable $out
}elseif($Mode -eq 2){
	Write-Verbose &quot;Расчет $(GetTypes $a) выполняется в режиме 2&quot;
	$jobs = @()
	$ScriptArguments_ = &quot;&quot;
	$PSBoundParameters.GetEnumerator() |
		Foreach-Object {if($_.Key -notmatch &#039;Path|MD5|SHA1|SHA256|SHA384|SHA512|Common|All|Mode|^Action$|GivenHash|ScriptArguments&#039;){
			$v = &quot;$($_.Value.ToString())&quot; -replace &quot;&#039;&quot;, &quot;&#039;&#039;&quot;
			$ScriptArguments_ += &quot;`n$($_.Key)=$(if($_.Value -eq $null){&#039;$null&#039;}else{&quot;[$($_.Value.GetType().Name)]&#039;$v&#039;&quot;})&quot;
		}}
	if($VerbosePreference -ne &#039;SilentlyContinue&#039; -and $ScriptArguments_ -notmatch &#039;\nVerbose=&#039;){
		$ScriptArguments_ += &quot;`nVerbosePreference=[String]&#039;$VerbosePreference&#039;&quot;
	}
	if($WarningPreference -ne &#039;Continue&#039; -and $ScriptArguments_ -notmatch &#039;\nWarningAction=&#039;){
		$ScriptArguments_ += &quot;`nWarningPreference=[String]&#039;$WarningPreference&#039;&quot;
	}
	if($ErrorActionPreference -ne &#039;Continue&#039; -and $ScriptArguments_ -notmatch &#039;\nErrorAction=&#039;){
		$ScriptArguments_ += &quot;`nErrorActionPreference=[String]&#039;$ErrorActionPreference&#039;&quot;
	}
	foreach($i in $a){$jobs += Start-Job -ScriptBlock {param($p1, $p2, $p3, $p4, $p5) $p=@{};
		(ConvertFrom-StringData $p5).GetEnumerator() | Foreach-Object {
			$v = $_.Value -replace &#039;\[SwitchParameter\]&#039;, &#039;[Boolean]&#039; -replace &#039;\[ActionPreference\]&#039;, &#039;[String]&#039;
			if($v -match &quot;^\[Boolean\]&#039;([^&#039;]+)&#039;$&quot;){$v = &#039;$&#039; + $Matches[1]}
			$p += Invoke-Expression &quot;@{$($_.Key)=$v}&quot;
		}
		&amp; &quot;$p1&quot; $p2 $p3 $p4 -ScriptArguments $p}`
		-ArgumentList $Script, $Path, &quot;$(if($i.value){&quot;Check&quot;})$($i.type)&quot;, &quot;$(if($i.value){$i.value})&quot;, $ScriptArguments_}
	if($jobs){try{$out = Wait-Job $jobs | Receive-Job}finally{Remove-Job $jobs -Force}}
	OutHashTable $out
}else{Throw &quot;Неизвестный режим:$Mode!&quot;}
</code></pre></div>]]></description>
			<author><![CDATA[null@example.com (kvk-2019)]]></author>
			<pubDate>Sat, 07 Dec 2019 19:59:07 +0000</pubDate>
			<guid>http://forum.script-coding.com/viewtopic.php?pid=136781#p136781</guid>
		</item>
	</channel>
</rss>
