assorted PowerShell recipes

See also: all the recipes and the intro

# setting up the powershell remoting
https://technet.microsoft.com/en-us/magazine/ff700227.aspx
# setting the limits for powershell remoting
https://stackoverflow.com/questions/13561730/maximum-data-size-in-a-remote-command
https://powershell.com/cs/media/p/7257.aspx\#using-custom-session-configurations

# Encrypting with RSA in PowerShell
https://powershell.org/wp/2014/02/01/revisited-powershell-and-encryption/
# encrypting with RSA
https://stackoverflow.com/questions/26300364/alternative-for-system-security-cryptography-pkcs-on-windows-mobile-6

# custom powershell object
https://social.technet.microsoft.com/wiki/contents/articles/7804.powershell-creating-custom-objects.aspx

# .NET/PowerShell string formatting
https://go.microsoft.com/fwlink/?LinkID=166451

# PowerShell function parameters
https://social.technet.microsoft.com/wiki/contents/articles/15994.powershell-advanced-function-parameter-attributes.aspx

# PowerShell classes
https://technet.microsoft.com/en-us/library/dn820211.aspx

# ArgumentTransformationAttribute - custom type casts for the cmdlet arguments
https://msdn.microsoft.com/en-us/library/system.management.automation.argumenttransformationattribute%28v=vs.85%29.aspx

# PowerShell issues on Github
https://github.com/powershell/powershell/issues

# Calling REST from full PowerShell
https://stackoverflow.com/questions/3574723/call-rest-api-from-powershell-script

# Get all possible values of an enum class
[Enum]::GetValues([System.Security.AccessControl.FileSystemRights])
# Build an Enum object from its int value
[Enum]::Parse([System.Security.AccessControl.FileSystemRights], 1)

# Finding the special paths from PowerShell (with enum Environment.SpecialFolder)
# (translates to SHGetKnownFolderPath())
[Environment]::GetFolderPath('LocalApplicationData')

# check in powershell if the user is elevated
$IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")

# Convert a base64 string to byte array
$bytes = [Convert]::FromBase64String("ABCDEFGH")
# convert the byte array to Unicode
[System.Text.Encoding]::Unicode.GetString($bytes)
# to encode Unicode as bytes
[System.Text.Encoding]::Unicode.GetBytes("abcd")

# Translate a windows error code to message in PowerShell
[ComponentModel.Win32Exception]$code

# Catch a custom exception thrown as a string
catch [System.Management.Automation.RuntimeException]

# check the value for being not $null (note: NO () after ToString)
if ($msg.ToString) { "zzz" }

# Translate the host name to adress (DNS lookup)
[System.Net.Dns]::GetHostEntry("host").AddressList[0].IpAddressToString
# Translate for IPv4 only
[System.Net.Dns]::GetHostEntry($Name).AddressList | ? {$_.AddressFamily -eq "InterNetwork"} | % {$_.IPAddressToString}
# easier with new PowerShell cmdlet but your luck with the PTR records may vary,
# they might not get automatically recursively resolved
@((Resolve-DnsName "host").IP4Address)[0]
@((Resolve-DnsName "host").IP6Address)[0]

# set the DNS configuration with PowerShell
Set-DnsClientServerAddress -InterfaceAlias "vEthernet (Mgmt)" -ServerAddresses @("")
set-dnsclient -ConnectionSpecificSuffix "" -interfacealias "vEthernet (Mgmt)"

# Get the event session information https://stackoverflow.com/questions/21012622/get-windows-event-provider-information
$EventSession = [System.Diagnostics.Eventing.Reader.EventLogSession]::GlobalSession;
$EventSession.GetProviderNames();
$EventSession.GetLogNames();
$prov = New-Object -TypeName System.Diagnostics.Eventing.Reader.ProviderMetadata -ArgumentList "Microsoft-Windows-BootEvent-Test-EvtGen"
$prov.Id # the GUID

# Catch all errors except the language errors
try {
throw zzz
} catch
[System.Management.Automation.ParseException],
[System.Management.Automation.CommandNotFoundException],
[System.Management.Automation.MethodInvocationException]
{
throw
} catch {
$e = $_
}

# l18n for PS scripts
Import-LocalizedData

# Copy files to a remote machine (Win10+)
Copy -ToSession $s ...
# Copy files from a remote machine (Win10+)
Copy -FromSession $s ...

# Create a custom PSObject
[PsCustomObject]@{ a=1; b=2; }

# remember the password credentials, password entered from keyboard
$cr = get-credential Administrator

# making a secure string from plain-text password
$ss = ConvertTo-SecureString -AsPlainText "P4ssw0rd" -Force
# Extracting the value from a SecureString - shorter version
(New-Object System.Net.NetworkCredential "",$ss).Password
# Extracting the value from a SecureString - longer version
$ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToGlobalAllocUnicode($ss)
$plain = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($ptr)
[System.Runtime.InteropServices.Marshal]::ZeroFreeGlobalAllocUnicode($ptr)
# Making a PS credential with a secure string password
$cr = New-Object System.Management.Automation.PSCredential @("Administrator", $ss)
# Making a session
$sess = new-pssession -ComputerName 169.254.81.127 -Credential $cr
# Running commands in a session
invoke-command -session $sess -ScriptBlock { bcdedit /enum }

# Create a script block from a string
$z = [ScriptBlock]::Create($sb.ToString())

# escape the regular expression characters
$str = [regex]::Escape($str)
# escape the XML characters
[System.Security.SecurityElement]::Escape($str)

# Get the tmp directory (per-user)
[System.IO.Path]::GetTempPath()
# Create a random file name (no directory part, really a random string)
$t = [System.IO.Path]::GetRandomFileName()
# Create cryptographically-random bytes (such as an AES encryption key)
$key = New-Object byte[](32)
$rng = [System.Security.Cryptography.RNGCryptoServiceProvider]::Create()
$rng.GetBytes($key)
# Generate a GUID
[System.Guid]::NewGuid().ToString()
# garbage-collect, useful before unloading a hive and such
[GC]::Collect()

# Show the results as a GUI table
Out-Grid
# as a GUI tree of object data
show-object

# Features needed to get VHD cmdlets from Hyper-V
dism /online /get-features | findstr "Hyper"
Microsoft-Hyper-V
Microsoft-Hyper-V-Offline
Microsoft-Hyper-V-Management-PowerShell /all
(and reboot afterwards)

# mount a share from powershell
New-PSDrive -Name Y -PSProvider FileSystem -Root \\host\shared -Credential domain\me

# How to discover the .NET APIs with PowerShell
$dll = [Reflection.Assembly]::LoadFile("C:\Program Files\dotnet\shared\Microsoft.NETCore.App\1.0.0\System.Runtime.Extensions.dll")
$dll.GetExportedTypes() | ft FullName
$dll.GetTypes() | ft FullName
$dll.GetType("System.Environment").GetMembers() | ft
# iterate through multiple DLLs, collecting the type names in all of them
$types = foreach ($f in (dir "C:\Program Files\dotnet\shared\Microsoft.NETCore.App\1.0.0\*.dll")) { try { $dll = [Reflection.Assembly]::LoadFile($f.FullName); foreach ($n in ($dll.GetExportedTypes().FullName)) { $
f.FullName + " " + $n}; } catch {} }
$types | ? { $_ -match "Environment" }

# print the methods of a type
[System.Threading.Timer].GetMembers()  | % { $_.ToString() }