PSUtility.psm1
|
function Get-LineEnding { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [string]$Path, [switch]$Recurse ) foreach ($p in Resolve-Path $Path -ErrorAction SilentlyContinue) { if (Test-Path $p -PathType "Container") { if ($Recurse) { Get-ChildItem -Path $p -File -Recurse:$Recurse | ForEach-Object { Get-LineEnding -Path $_.FullName } } continue; } $content = [IO.File]::ReadAllText($p) $EOLType = if ($content.Contains("`r`n")) { "CRLF" } elseif ($content.Contains("`r")) { "CR" } elseif ($content.Contains("`n")) { "LF" } else { "None" } [PSCustomObject]@{ Name = [IO.Path]::GetFileName($p) Type = $EOLType Path = $p.Path } } } function Get-FileLength { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [string]$Path, [switch]$Recurse, [Parameter(Mandatory=$false)] [ValidateSet("KB", "MB", "GB")] [string]$Unit ) $divisor = switch ($Unit) { "KB" { 1KB } "MB" { 1MB } "GB" { 1GB } default { $null } } foreach ($p in Resolve-Path $Path -ErrorAction SilentlyContinue) { if (Test-Path $p -PathType "Container") { if ($Recurse) { Get-ChildItem -Path $p -File -Recurse:$Recurse | ForEach-Object { Get-FileLength -Path $_.FullName -Unit $Unit } } else { Write-Warning "'$p' is a directory. Use -Recurse to include its contents" } } $file = Get-Item $p $length = $divisor ? $file.length / $divisor : $file.length [PSCustomObject]@{ Name = [IO.Path]::GetFileName($p) Length = $Length Unit = $Unit ? $Unit : "Bytes" Path = $p.Path } } } function Invoke-Environment { [CmdletBinding()] param ( [Parameter(Mandatory=$True)] [string] $cmd ) cmd /c "`"$cmd`" > nul 2>&1 && set" | . { process { if ($_ -match "^([^=]+)=(.*)") { [Environment]::SetEnvironmentVariable($matches[1], $matches[2], "Process") } }} } function Set-MSVCEnvironment { [CmdletBinding()] param () $Env:VSCMD_ARG_HOST_ARCH = "x64" $Env:VSCMD_ARG_TGT_ARCH = "x64" $Env:VSCMD_ARG_APP_PLAT = "Desktop" # Fun fact: jika kita remove trailing slash-nya, entah kenapa bakal error, cool... Windows amirite? $Env:VSINSTALLDIR = "C:\Program Files\Microsoft Visual Studio\18\Community\" Invoke-Environment (Join-Path $Env:VSINSTALLDIR "\Common7\Tools\vsdevcmd\ext\vcvars.bat") Invoke-Environment (Join-Path $Env:VSINSTALLDIR "\Common7\Tools\vsdevcmd\core\winsdk.bat") $Env:INCLUDE = @( $Env:__VSCMD_VCVARS_INCLUDE, $Env:__VSCMD_WINSDK_INCLUDE, $Env:__VSCMD_NETFX_INCLUDE ) -join ";" } function Resolve-NtStatus { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [int]$NtStatus ) if (-not ([Management.Automation.PSTypeName]'NtDll.NtStatus').Type) { Add-Type -TypeDefinition @' using System.Runtime.InteropServices; namespace NtDll { public class NtStatus { [DllImport("ntdll.dll")] public static extern uint RtlNtStatusToDosError(uint status); } } '@ } # Cast [uint32] di .NET melakukan pengecekan nilai, bukan reinterpretasi bit sehingga # casting int negatif langsung ke uint32 raise exception. Maka, kita bit-AND dengan 0xFFFFFFFF: # 1. PowerShell mempromosikan kedua operand ke [long] (64-bit), melakukan sign-extension # pada int (mengisi 32 bit atas dengan 1 karena MSB bernilai 1) # 2. 0xFFFFFFFF me-mask 32 bit atas tersebut, menyisakan hanya 32 bit bawah yang asli # 3. Hasilnya sekarang berupa [long] positif yang dapat di-cast ke [uint32] sesuai ekspetasi $uNtStatus = [uint32]($NtStatus -band 0xFFFFFFFFL) $errorCode = [NtDll.NtStatus]::RtlNtStatusToDosError($uNtStatus) # Convert win32 error code menjadi human readable message. # Kita perlu cast [int] karena constructor `Win32Exception` expect int sbgai param $message = ([ComponentModel.Win32Exception][int]$errorCode).Message [PSCustomObject]@{ Status = "0x$("{0:X8}" -f $NtStatus)" Win32ErrorCode = $errorCode Description = $message } } New-Alias -Name gle -Value Get-LineEnding New-Alias -Name gfl -Value Get-FileLength Export-ModuleMember -Function * -Alias * |