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