github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cloudconfig/winuserdata.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Copyright 2016 Cloudbase Solutions SRL 3 // Licensed under the AGPLv3, see LICENCE file for details. 4 5 package cloudconfig 6 7 // Generated code - do not edit. 8 9 const addJujuUser = ` 10 function create-account ([string]$accountName, [string]$accountDescription, [string]$password) { 11 $hostname = hostname 12 $comp = [adsi]"WinNT://$hostname" 13 $user = $comp.Create("User", $accountName) 14 $user.SetPassword($password) 15 $user.SetInfo() 16 $user.description = $accountDescription 17 $user.SetInfo() 18 $User.UserFlags[0] = $User.UserFlags[0] -bor 0x10000 19 $user.SetInfo() 20 21 # This gets the Administrator group name that is localized on different windows versions. 22 # However the SID S-1-5-32-544 is the same on all versions. 23 $adminGroup = (New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544")).Translate([System.Security.Principal.NTAccount]).Value.Split("\")[1] 24 25 $objOU = [ADSI]"WinNT://$hostname/$adminGroup,group" 26 $objOU.add("WinNT://$hostname/$accountName") 27 } 28 29 $Source = @" 30 using System; 31 using System.Text; 32 using System.Runtime.InteropServices; 33 34 namespace PSCloudbase 35 { 36 public sealed class Win32CryptApi 37 { 38 public static long CRYPT_SILENT = 0x00000040; 39 public static long CRYPT_VERIFYCONTEXT = 0xF0000000; 40 public static int PROV_RSA_FULL = 1; 41 42 [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] 43 [return : MarshalAs(UnmanagedType.Bool)] 44 public static extern bool CryptAcquireContext(ref IntPtr hProv, 45 StringBuilder pszContainer, // Don't use string, as Powershell replaces $null with an empty string 46 StringBuilder pszProvider, // Don't use string, as Powershell replaces $null with an empty string 47 uint dwProvType, 48 uint dwFlags); 49 50 [DllImport("Advapi32.dll", EntryPoint = "CryptReleaseContext", CharSet = CharSet.Unicode, SetLastError = true)] 51 public static extern bool CryptReleaseContext(IntPtr hProv, Int32 dwFlags); 52 53 [DllImport("advapi32.dll", SetLastError=true)] 54 public static extern bool CryptGenRandom(IntPtr hProv, uint dwLen, byte[] pbBuffer); 55 56 [DllImport("Kernel32.dll")] 57 public static extern uint GetLastError(); 58 } 59 } 60 "@ 61 62 Add-Type -TypeDefinition $Source -Language CSharp 63 64 function Get-RandomPassword 65 { 66 [CmdletBinding()] 67 param 68 ( 69 [parameter(Mandatory=$true)] 70 [int]$Length 71 ) 72 process 73 { 74 $hProvider = 0 75 try 76 { 77 if(![PSCloudbase.Win32CryptApi]::CryptAcquireContext([ref]$hProvider, $null, $null, 78 [PSCloudbase.Win32CryptApi]::PROV_RSA_FULL, 79 ([PSCloudbase.Win32CryptApi]::CRYPT_VERIFYCONTEXT -bor 80 [PSCloudbase.Win32CryptApi]::CRYPT_SILENT))) 81 { 82 throw "CryptAcquireContext failed with error: 0x" + "{0:X0}" -f [PSCloudbase.Win32CryptApi]::GetLastError() 83 } 84 85 $buffer = New-Object byte[] $Length 86 if(![PSCloudbase.Win32CryptApi]::CryptGenRandom($hProvider, $Length, $buffer)) 87 { 88 throw "CryptGenRandom failed with error: 0x" + "{0:X0}" -f [PSCloudbase.Win32CryptApi]::GetLastError() 89 } 90 91 $buffer | ForEach-Object { $password += "{0:X0}" -f $_ } 92 return $password 93 } 94 finally 95 { 96 if($hProvider) 97 { 98 $retVal = [PSCloudbase.Win32CryptApi]::CryptReleaseContext($hProvider, 0) 99 } 100 } 101 } 102 } 103 $SourcePolicy = @" 104 /* 105 Original sources available at: https://bitbucket.org/splatteredbits/carbon 106 */ 107 108 using System; 109 using System.Collections.Generic; 110 using System.ComponentModel; 111 using System.Runtime.InteropServices; 112 using System.Security.Principal; 113 using System.Text; 114 115 namespace PSCarbon 116 { 117 public sealed class Lsa 118 { 119 // ReSharper disable InconsistentNaming 120 [StructLayout(LayoutKind.Sequential)] 121 internal struct LSA_UNICODE_STRING 122 { 123 internal LSA_UNICODE_STRING(string inputString) 124 { 125 if (inputString == null) 126 { 127 Buffer = IntPtr.Zero; 128 Length = 0; 129 MaximumLength = 0; 130 } 131 else 132 { 133 Buffer = Marshal.StringToHGlobalAuto(inputString); 134 Length = (ushort)(inputString.Length * UnicodeEncoding.CharSize); 135 MaximumLength = (ushort)((inputString.Length + 1) * UnicodeEncoding.CharSize); 136 } 137 } 138 139 internal ushort Length; 140 internal ushort MaximumLength; 141 internal IntPtr Buffer; 142 } 143 144 [StructLayout(LayoutKind.Sequential)] 145 internal struct LSA_OBJECT_ATTRIBUTES 146 { 147 internal uint Length; 148 internal IntPtr RootDirectory; 149 internal LSA_UNICODE_STRING ObjectName; 150 internal uint Attributes; 151 internal IntPtr SecurityDescriptor; 152 internal IntPtr SecurityQualityOfService; 153 } 154 155 [StructLayout(LayoutKind.Sequential)] 156 public struct LUID 157 { 158 public uint LowPart; 159 public int HighPart; 160 } 161 162 // ReSharper disable UnusedMember.Local 163 private const uint POLICY_VIEW_LOCAL_INFORMATION = 0x00000001; 164 private const uint POLICY_VIEW_AUDIT_INFORMATION = 0x00000002; 165 private const uint POLICY_GET_PRIVATE_INFORMATION = 0x00000004; 166 private const uint POLICY_TRUST_ADMIN = 0x00000008; 167 private const uint POLICY_CREATE_ACCOUNT = 0x00000010; 168 private const uint POLICY_CREATE_SECRET = 0x00000014; 169 private const uint POLICY_CREATE_PRIVILEGE = 0x00000040; 170 private const uint POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080; 171 private const uint POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100; 172 private const uint POLICY_AUDIT_LOG_ADMIN = 0x00000200; 173 private const uint POLICY_SERVER_ADMIN = 0x00000400; 174 private const uint POLICY_LOOKUP_NAMES = 0x00000800; 175 private const uint POLICY_NOTIFICATION = 0x00001000; 176 // ReSharper restore UnusedMember.Local 177 178 [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 179 public static extern bool LookupPrivilegeValue( 180 [MarshalAs(UnmanagedType.LPTStr)] string lpSystemName, 181 [MarshalAs(UnmanagedType.LPTStr)] string lpName, 182 out LUID lpLuid); 183 184 [DllImport("advapi32.dll", CharSet = CharSet.Unicode)] 185 private static extern uint LsaAddAccountRights( 186 IntPtr PolicyHandle, 187 IntPtr AccountSid, 188 LSA_UNICODE_STRING[] UserRights, 189 uint CountOfRights); 190 191 [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = false)] 192 private static extern uint LsaClose(IntPtr ObjectHandle); 193 194 [DllImport("advapi32.dll", SetLastError = true)] 195 private static extern uint LsaEnumerateAccountRights(IntPtr PolicyHandle, 196 IntPtr AccountSid, 197 out IntPtr UserRights, 198 out uint CountOfRights 199 ); 200 201 [DllImport("advapi32.dll", SetLastError = true)] 202 private static extern uint LsaFreeMemory(IntPtr pBuffer); 203 204 [DllImport("advapi32.dll")] 205 private static extern int LsaNtStatusToWinError(long status); 206 207 [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)] 208 private static extern uint LsaOpenPolicy(ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, uint DesiredAccess, out IntPtr PolicyHandle ); 209 210 [DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)] 211 static extern uint LsaRemoveAccountRights( 212 IntPtr PolicyHandle, 213 IntPtr AccountSid, 214 [MarshalAs(UnmanagedType.U1)] 215 bool AllRights, 216 LSA_UNICODE_STRING[] UserRights, 217 uint CountOfRights); 218 // ReSharper restore InconsistentNaming 219 220 private static IntPtr GetIdentitySid(string identity) 221 { 222 SecurityIdentifier sid = 223 new NTAccount(identity).Translate(typeof (SecurityIdentifier)) as SecurityIdentifier; 224 if (sid == null) 225 { 226 throw new ArgumentException(string.Format("Account {0} not found.", identity)); 227 } 228 byte[] sidBytes = new byte[sid.BinaryLength]; 229 sid.GetBinaryForm(sidBytes, 0); 230 System.IntPtr sidPtr = Marshal.AllocHGlobal(sidBytes.Length); 231 Marshal.Copy(sidBytes, 0, sidPtr, sidBytes.Length); 232 return sidPtr; 233 } 234 235 private static IntPtr GetLsaPolicyHandle() 236 { 237 string computerName = Environment.MachineName; 238 IntPtr hPolicy; 239 LSA_OBJECT_ATTRIBUTES objectAttributes = new LSA_OBJECT_ATTRIBUTES(); 240 objectAttributes.Length = 0; 241 objectAttributes.RootDirectory = IntPtr.Zero; 242 objectAttributes.Attributes = 0; 243 objectAttributes.SecurityDescriptor = IntPtr.Zero; 244 objectAttributes.SecurityQualityOfService = IntPtr.Zero; 245 246 const uint ACCESS_MASK = POLICY_CREATE_SECRET | POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION; 247 LSA_UNICODE_STRING machineNameLsa = new LSA_UNICODE_STRING(computerName); 248 uint result = LsaOpenPolicy(ref machineNameLsa, ref objectAttributes, ACCESS_MASK, out hPolicy); 249 HandleLsaResult(result); 250 return hPolicy; 251 } 252 253 public static string[] GetPrivileges(string identity) 254 { 255 IntPtr sidPtr = GetIdentitySid(identity); 256 IntPtr hPolicy = GetLsaPolicyHandle(); 257 IntPtr rightsPtr = IntPtr.Zero; 258 259 try 260 { 261 262 List<string> privileges = new List<string>(); 263 264 uint rightsCount; 265 uint result = LsaEnumerateAccountRights(hPolicy, sidPtr, out rightsPtr, out rightsCount); 266 int win32ErrorCode = LsaNtStatusToWinError(result); 267 // the user has no privileges 268 if( win32ErrorCode == STATUS_OBJECT_NAME_NOT_FOUND ) 269 { 270 return new string[0]; 271 } 272 HandleLsaResult(result); 273 274 LSA_UNICODE_STRING myLsaus = new LSA_UNICODE_STRING(); 275 for (ulong i = 0; i < rightsCount; i++) 276 { 277 IntPtr itemAddr = new IntPtr(rightsPtr.ToInt64() + (long) (i*(ulong) Marshal.SizeOf(myLsaus))); 278 myLsaus = (LSA_UNICODE_STRING) Marshal.PtrToStructure(itemAddr, myLsaus.GetType()); 279 char[] cvt = new char[myLsaus.Length/UnicodeEncoding.CharSize]; 280 Marshal.Copy(myLsaus.Buffer, cvt, 0, myLsaus.Length/UnicodeEncoding.CharSize); 281 string thisRight = new string(cvt); 282 privileges.Add(thisRight); 283 } 284 return privileges.ToArray(); 285 } 286 finally 287 { 288 Marshal.FreeHGlobal(sidPtr); 289 uint result = LsaClose(hPolicy); 290 HandleLsaResult(result); 291 result = LsaFreeMemory(rightsPtr); 292 HandleLsaResult(result); 293 } 294 } 295 296 public static void GrantPrivileges(string identity, string[] privileges) 297 { 298 IntPtr sidPtr = GetIdentitySid(identity); 299 IntPtr hPolicy = GetLsaPolicyHandle(); 300 301 try 302 { 303 LSA_UNICODE_STRING[] lsaPrivileges = StringsToLsaStrings(privileges); 304 uint result = LsaAddAccountRights(hPolicy, sidPtr, lsaPrivileges, (uint)lsaPrivileges.Length); 305 HandleLsaResult(result); 306 } 307 finally 308 { 309 Marshal.FreeHGlobal(sidPtr); 310 uint result = LsaClose(hPolicy); 311 HandleLsaResult(result); 312 } 313 } 314 315 const int STATUS_SUCCESS = 0x0; 316 const int STATUS_OBJECT_NAME_NOT_FOUND = 0x00000002; 317 const int STATUS_ACCESS_DENIED = 0x00000005; 318 const int STATUS_INVALID_HANDLE = 0x00000006; 319 const int STATUS_UNSUCCESSFUL = 0x0000001F; 320 const int STATUS_INVALID_PARAMETER = 0x00000057; 321 const int STATUS_NO_SUCH_PRIVILEGE = 0x00000521; 322 const int STATUS_INVALID_SERVER_STATE = 0x00000548; 323 const int STATUS_INTERNAL_DB_ERROR = 0x00000567; 324 const int STATUS_INSUFFICIENT_RESOURCES = 0x000005AA; 325 326 private static Dictionary<int, string> ErrorMessages = new Dictionary<int, string>(); 327 public Lsa () { 328 ErrorMessages.Add(STATUS_ACCESS_DENIED, "Access denied. Caller does not have the appropriate access to complete the operation."); 329 ErrorMessages.Add(STATUS_INVALID_HANDLE, "Invalid handle. Indicates an object or RPC handle is not valid in the context used."); 330 ErrorMessages.Add(STATUS_UNSUCCESSFUL, "Unsuccessful. Generic failure, such as RPC connection failure."); 331 ErrorMessages.Add(STATUS_INVALID_PARAMETER, "Invalid parameter. One of the parameters is not valid."); 332 ErrorMessages.Add(STATUS_NO_SUCH_PRIVILEGE, "No such privilege. Indicates a specified privilege does not exist."); 333 ErrorMessages.Add(STATUS_INVALID_SERVER_STATE, "Invalid server state. Indicates the LSA server is currently disabled."); 334 ErrorMessages.Add(STATUS_INTERNAL_DB_ERROR, "Internal database error. The LSA database contains an internal inconsistency."); 335 ErrorMessages.Add(STATUS_INSUFFICIENT_RESOURCES, "Insufficient resources. There are not enough system resources (such as memory to allocate buffers) to complete the call."); 336 ErrorMessages.Add(STATUS_OBJECT_NAME_NOT_FOUND, "Object name not found. An object in the LSA policy database was not found. The object may have been specified either by SID or by name, depending on its type."); 337 } 338 339 private static void HandleLsaResult(uint returnCode) 340 { 341 int win32ErrorCode = LsaNtStatusToWinError(returnCode); 342 343 if( win32ErrorCode == STATUS_SUCCESS) 344 return; 345 346 if( ErrorMessages.ContainsKey(win32ErrorCode) ) 347 { 348 throw new Win32Exception(win32ErrorCode, ErrorMessages[win32ErrorCode]); 349 } 350 351 throw new Win32Exception(win32ErrorCode); 352 } 353 354 public static void RevokePrivileges(string identity, string[] privileges) 355 { 356 IntPtr sidPtr = GetIdentitySid(identity); 357 IntPtr hPolicy = GetLsaPolicyHandle(); 358 359 try 360 { 361 string[] currentPrivileges = GetPrivileges(identity); 362 if (currentPrivileges.Length == 0) 363 { 364 return; 365 } 366 LSA_UNICODE_STRING[] lsaPrivileges = StringsToLsaStrings(privileges); 367 uint result = LsaRemoveAccountRights(hPolicy, sidPtr, false, lsaPrivileges, (uint)lsaPrivileges.Length); 368 HandleLsaResult(result); 369 } 370 finally 371 { 372 Marshal.FreeHGlobal(sidPtr); 373 uint result = LsaClose(hPolicy); 374 HandleLsaResult(result); 375 } 376 377 } 378 379 private static LSA_UNICODE_STRING[] StringsToLsaStrings(string[] privileges) 380 { 381 LSA_UNICODE_STRING[] lsaPrivileges = new LSA_UNICODE_STRING[privileges.Length]; 382 for (int idx = 0; idx < privileges.Length; ++idx) 383 { 384 lsaPrivileges[idx] = new LSA_UNICODE_STRING(privileges[idx]); 385 } 386 return lsaPrivileges; 387 } 388 } 389 } 390 "@ 391 Add-Type -TypeDefinition $SourcePolicy -Language CSharp 392 393 function SetAssignPrimaryTokenPrivilege($UserName) 394 { 395 $privilege = "SeAssignPrimaryTokenPrivilege" 396 if (!([PSCarbon.Lsa]::GetPrivileges($UserName) -contains $privilege)) 397 { 398 [PSCarbon.Lsa]::GrantPrivileges($UserName, $privilege) 399 } 400 } 401 402 function SetUserLogonAsServiceRights($UserName) 403 { 404 $privilege = "SeServiceLogonRight" 405 if (!([PSCarbon.Lsa]::GetPrivileges($UserName) -Contains $privilege)) 406 { 407 [PSCarbon.Lsa]::GrantPrivileges($UserName, $privilege) 408 } 409 } 410 function Test-RegistryValue { 411 param ([parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()]$Path, 412 [parameter(Mandatory=$true)] 413 [ValidateNotNullOrEmpty()]$Value) 414 try { 415 Get-ItemProperty -Path $Path | Select-Object -ExpandProperty $Value -ErrorAction Stop | Out-Null 416 return $true 417 }catch {return $false} 418 } 419 $juju_passwd = Get-RandomPassword 20 420 $juju_passwd += "^" 421 if (& net users | select-string "jujud") { 422 net user "jujud" /DELETE 423 } 424 create-account jujud "Juju Admin user" $juju_passwd 425 $hostname = hostname 426 $juju_user = "$hostname\jujud" 427 SetUserLogonAsServiceRights $juju_user 428 SetAssignPrimaryTokenPrivilege $juju_user 429 $path = "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList" 430 if (Test-RegistryValue -Path $path -Value "jujud") { 431 Remove-ItemProperty -Path $path -Name "jujud" 432 } 433 if(!(Test-Path $path)){ 434 New-Item -Path $path -force 435 } 436 if(Test-Path "C:\Juju") { 437 rm -Recurse -Force "C:\Juju" 438 } 439 if(Test-Path "HKLM:\SOFTWARE\juju-core") { 440 Remove-Item -Path "HKLM:\SOFTWARE\juju-core" -Recurse -Force 441 } 442 New-ItemProperty $path -Name "jujud" -Value 0 -PropertyType "DWord" 443 $secpasswd = ConvertTo-SecureString $juju_passwd -AsPlainText -Force 444 $jujuCreds = New-Object System.Management.Automation.PSCredential ($juju_user, $secpasswd) 445 ` 446 const windowsPowershellHelpers = ` 447 448 $ErrorActionPreference = "Stop" 449 450 function ExecRetry($command, $retryInterval = 15) 451 { 452 $currErrorActionPreference = $ErrorActionPreference 453 $ErrorActionPreference = "Continue" 454 455 while ($true) 456 { 457 try 458 { 459 & $command 460 break 461 } 462 catch [System.Exception] 463 { 464 Write-Error $_.Exception 465 Start-Sleep $retryInterval 466 } 467 } 468 469 $ErrorActionPreference = $currErrorActionPreference 470 } 471 472 # TryExecAll attempts all of the commands in the supplied array until 473 # one can be executed without throwing an exception. If none of the 474 # commands succeeds, an exception will be raised. 475 function TryExecAll($commands) 476 { 477 $currErrorActionPreference = $ErrorActionPreference 478 $ErrorActionPreference = "Continue" 479 480 foreach ($command in $commands) 481 { 482 try 483 { 484 & $command 485 $ErrorActionPreference = $currErrorActionPreference 486 return 487 } 488 catch [System.Exception] 489 { 490 Write-Error $_.Exception 491 } 492 } 493 494 $ErrorActionPreference = $currErrorActionPreference 495 throw "All commands failed" 496 } 497 498 Function GUnZip-File{ 499 Param( 500 $infile, 501 $outdir 502 ) 503 504 $input = New-Object System.IO.FileStream $inFile, ([IO.FileMode]::Open), ([IO.FileAccess]::Read), ([IO.FileShare]::Read) 505 $tempFile = "$env:TEMP\jujud.tar" 506 $tempOut = New-Object System.IO.FileStream $tempFile, ([IO.FileMode]::Create), ([IO.FileAccess]::Write), ([IO.FileShare]::None) 507 $gzipStream = New-Object System.IO.Compression.GzipStream $input, ([IO.Compression.CompressionMode]::Decompress) 508 509 $buffer = New-Object byte[](1024) 510 while($true) { 511 $read = $gzipstream.Read($buffer, 0, 1024) 512 if ($read -le 0){break} 513 $tempOut.Write($buffer, 0, $read) 514 } 515 $gzipStream.Close() 516 $tempOut.Close() 517 $input.Close() 518 519 $in = New-Object System.IO.FileStream $tempFile, ([IO.FileMode]::Open), ([IO.FileAccess]::Read), ([IO.FileShare]::Read) 520 Untar-File $in $outdir 521 $in.Close() 522 rm $tempFile 523 } 524 525 $HEADERSIZE = 512 526 527 Function Untar-File { 528 Param( 529 $inStream, 530 $outdir 531 ) 532 $DirectoryEntryType = 0x35 533 $headerBytes = New-Object byte[]($HEADERSIZE) 534 535 # $headerBytes is written inside, function returns whether we've reached the end 536 while(GetHeaderBytes $inStream $headerBytes) { 537 $fileName, $entryType, $sizeInBytes = GetFileInfoFromHeader $headerBytes 538 539 $totalPath = Join-Path $outDir $fileName 540 if ($entryType -eq $DirectoryEntryType) { 541 [System.IO.Directory]::CreateDirectory($totalPath) 542 continue; 543 } 544 545 $fName = [System.IO.Path]::GetFileName($totalPath) 546 $dirName = [System.IO.Path]::GetDirectoryName($totalPath) 547 [System.IO.Directory]::CreateDirectory($dirName) 548 $file = [System.IO.File]::Create($totalPath) 549 WriteTarEntryToFile $inStream $file $sizeInBytes 550 $file.Close() 551 } 552 } 553 554 Function WriteTarEntryToFile { 555 Param( 556 $inStream, 557 $outFile, 558 $sizeInBytes 559 ) 560 $moveToAlign512 = 0 561 $toRead = 0 562 $buf = New-Object byte[](512) 563 564 $remainingBytesInFile = $sizeInBytes 565 while ($remainingBytesInFile -ne 0) { 566 if ($remainingBytesInFile - 512 -lt 0) { 567 $moveToAlign512 = 512 - $remainingBytesInFile 568 $toRead = $remainingBytesInFile 569 } else { 570 $toRead = 512 571 } 572 573 $bytesRead = 0 574 $bytesRemainingToRead = $toRead 575 while ($bytesRead -lt $toRead -and $bytesRemainingToRead -gt 0) { 576 $bytesRead = $inStream.Read($buf, $toRead - $bytesRemainingToRead, $bytesRemainingToRead) 577 $bytesRemainingToRead = $bytesRemainingToRead - $bytesRead 578 $remainingBytesInFile = $remainingBytesInFile - $bytesRead 579 $outFile.Write($buf, 0, $bytesRead) 580 } 581 582 if ($moveToAlign512 -ne 0) { 583 $inStream.Seek($moveToAlign512, [System.IO.SeekOrigin]::Current) 584 } 585 } 586 } 587 588 Function GetHeaderBytes { 589 Param($inStream, $headerBytes) 590 591 $headerRead = 0 592 $bytesRemaining = $HEADERSIZE 593 while ($bytesRemaining -gt 0) { 594 $headerRead = $inStream.Read($headerBytes, $HEADERSIZE - $bytesRemaining, $bytesRemaining) 595 $bytesRemaining -= $headerRead 596 if ($headerRead -le 0 -and $bytesRemaining -gt 0) { 597 throw "Error reading tar header. Header size invalid" 598 } 599 } 600 601 # Proper end of archive is 2 empty headers 602 if (IsEmptyByteArray $headerBytes) { 603 $bytesRemaining = $HEADERSIZE 604 while ($bytesRemaining -gt 0) { 605 $headerRead = $inStream.Read($headerBytes, $HEADERSIZE - $bytesRemaining, $bytesRemaining) 606 $bytesRemaining -= $headerRead 607 if ($headerRead -le 0 -and $bytesRemaining -gt 0) { 608 throw "Broken end archive" 609 } 610 } 611 if ($bytesRemaining -eq 0 -and (IsEmptyByteArray($headerBytes))) { 612 return $false 613 } 614 throw "Error occurred: expected end of archive" 615 } 616 617 return $true 618 } 619 620 Function GetFileInfoFromHeader { 621 Param($headerBytes) 622 623 $FileName = [System.Text.Encoding]::UTF8.GetString($headerBytes, 0, 100); 624 $EntryType = $headerBytes[156]; 625 $SizeInBytes = [Convert]::ToInt64([System.Text.Encoding]::ASCII.GetString($headerBytes, 124, 11).Trim(), 8); 626 Return $FileName.replace("` + "`" + `0", [String].Empty), $EntryType, $SizeInBytes 627 } 628 629 Function IsEmptyByteArray { 630 Param ($bytes) 631 foreach($b in $bytes) { 632 if ($b -ne 0) { 633 return $false 634 } 635 } 636 return $true 637 } 638 639 Function Get-FileSHA256{ 640 Param( 641 $FilePath 642 ) 643 try { 644 $hash = [Security.Cryptography.HashAlgorithm]::Create( "SHA256" ) 645 $stream = ([IO.StreamReader]$FilePath).BaseStream 646 $res = -join ($hash.ComputeHash($stream) | ForEach { "{0:x2}" -f $_ }) 647 $stream.Close() 648 return $res 649 } catch [System.Management.Automation.RuntimeException] { 650 return (Get-FileHash -Path $FilePath).Hash 651 } 652 } 653 654 Function Invoke-FastWebRequest { 655 Param( 656 $URI, 657 $OutFile 658 ) 659 660 if(!([System.Management.Automation.PSTypeName]'System.Net.Http.HttpClient').Type) 661 { 662 $assembly = [System.Reflection.Assembly]::LoadWithPartialName("System.Net.Http") 663 } 664 665 $client = new-object System.Net.Http.HttpClient 666 667 $task = $client.GetStreamAsync($URI) 668 $response = $task.Result 669 $outStream = New-Object IO.FileStream $OutFile, Create, Write, None 670 671 try { 672 $totRead = 0 673 $buffer = New-Object Byte[] 1MB 674 while (($read = $response.Read($buffer, 0, $buffer.Length)) -gt 0) { 675 $totRead += $read 676 $outStream.Write($buffer, 0, $read); 677 } 678 } 679 finally { 680 $outStream.Close() 681 } 682 } 683 684 `