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  `