Advertisement
Old-Lost

Out-FileUtf8NoBom

Jul 19th, 2017
97
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <#
  2. .SYNOPSIS
  3. Outputs to a UTF-8-encoded file *without a BOM* (byte-order mark).
  4.  
  5. .DESCRIPTION
  6. Mimics the most important aspects of Out-File:
  7. * Input objects are sent to Out-String first.
  8. * -Append allows you to append to an existing file, -NoClobber prevents
  9. overwriting of an existing file.
  10. * -Width allows you to specify the line width for the text representations
  11. of input objects that aren't strings.
  12. However, it is not a complete implementation of all Out-String parameters:
  13. * Only a literal output path is supported, and only as a parameter.
  14. * -Force is not supported.
  15.  
  16. Caveat: *All* pipeline input is buffered before writing output starts,
  17. but the string representations are generated and written to the target
  18. file one by one.
  19.  
  20. .NOTES
  21. The raison d'Γͺtre for this advanced function is that, as of PowerShell v5,
  22. Out-File still lacks the ability to write UTF-8 files without a BOM:
  23. using -Encoding UTF8 invariably prepends a BOM.
  24.  
  25. #>
  26. function Out-FileUtf8NoBom {
  27.  
  28.     [CmdletBinding()]
  29.     param(
  30.         [Parameter(Mandatory, Position = 0)] [string] $LiteralPath,
  31.         [switch] $Append,
  32.         [switch] $NoClobber,
  33.         [AllowNull()] [int] $Width,
  34.         [Parameter(ValueFromPipeline)] $InputObject
  35.     )
  36.  
  37.     #requires -version 3
  38.  
  39.     # Make sure that the .NET framework sees the same working dir. as PS
  40.     # and resolve the input path to a full path.
  41.     [System.IO.Directory]::SetCurrentDirectory($PWD) # Caveat: .NET Core doesn't support [Environment]::CurrentDirectory
  42.     $LiteralPath = [IO.Path]::GetFullPath($LiteralPath)
  43.  
  44.     # If -NoClobber was specified, throw an exception if the target file already
  45.     # exists.
  46.     if ($NoClobber -and (Test-Path $LiteralPath)) {
  47.         Throw [IO.IOException] "The file '$LiteralPath' already exists."
  48.     }
  49.  
  50.     # Create a StreamWriter object.
  51.     # Note that we take advantage of the fact that the StreamWriter class by default:
  52.     # - uses UTF-8 encoding
  53.     # - without a BOM.
  54.     $sw = New-Object IO.StreamWriter $LiteralPath, $Append
  55.  
  56.     $htOutStringArgs = @{}
  57.     if ($Width) {
  58.         $htOutStringArgs += @{ Width = $Width }
  59.     }
  60.  
  61.     # Note: By not using begin / process / end blocks, we're effectively running
  62.     #       in the end block, which means that all pipeline input has already
  63.     #       been collected in automatic variable $Input.
  64.     #       We must use this approach, because using | Out-String individually
  65.     #       in each iteration of a process block would format each input object
  66.     #       with an individual header.
  67.     try {
  68.         $Input | Out-String -Stream @htOutStringArgs | % { $sw.WriteLine($_) }
  69.     } finally {
  70.         $sw.Dispose()
  71.     }
  72. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement