PowerShell Function To Add Filesystem Permissions

Recently wrote a simple function to add permission to filesystem resources. It defaults to modify permissions, but can also be another basic permission for instance: Read, Write or FullControl.

function fnAddFilesystemPermissions()
{
  param (
    [string]$sPath,
	[string]$sUserName,
	[string]$sPermission = "Modify"
  )

  # Add write permissions to a file using powershell...
  $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($sUserName,$sPermission,"Allow")
  $acl = Get-ACL -Path $sPath
  $acl.SetAccessRule($accessRule)
  $acl | Set-Acl -Path $sPath

  # Return permissions...
  return (Get-ACL -Path $sPath).Access | Format-Table 
}

PS> fnAddFilesystemPermissions -sPath “C:\Path\To\Resource” -sUserName “User-Principle-Name” [-sPermission “FullControl“]

[Other] Start DevOps Tools From Command line

Some commands I regularly use to start tools from the command line when I need them to start with elevated privileges.

My Frequently Used CLI Commands / Admin Tools (QuickRef)Description
dsa.msc / adsiedit.msc / virtmgmt.msc Active Directory Users & Computers / ADSI Edit / Hyper-V Manager
start-process powershell -verb runasStart PowerShell with Elevated Privileges
rundll32 sysdm.cpl,EditEnvironmentVariablesEdit Windows system environment variables
cacls “C:\Path\To\File.TXT” /E /G username@example.com:CQuick way to add write permission to a filesystem resource
java -Djavax.net.debug=ssl:handshake -jar target/packagename-1.0.0-SNAPSHOT.jarStart package with TLS handshake debugging enabled

PowerShell Sftp Retrieve multiple Files (and Remove Source files)

The PowerShell script below retrieves multiple files from a SFTP server source using the native windows SFTP-client in windows After retrieving each individual file it removes the file from the SFTP-server. This specific script makes us of a (preconfigured) ssh-key authentication configuration, but it can easily been rewritten for password authentication.

<#
    Description    : Retrieve (get) and remove files from a sftp source... 
    Keywords       : Sftp, Get and Remove Original, Move

    Majorversion   : 1
    Scriptserver   : LOCALHOST
    Serviceaccount : -

    Author         : Tim van Kooten Niekerk
    Date           : 2023-03-14
#>

<#      CHANGELOG:
        2023-03-14 => Initieel (Tim van Kooten Niekerk)

#>


function fnMoveSftpFiles()
{
  param(
    [string]$sSftpServerHost,
    [string]$sSftpUser,
    [string]$sSftpServerPort = "22",
    [string]$sSftpRemoteFilePath,
    [string]$sSftpRemoteFileMask,
    [string]$sSftpLocalFilePath,
    [string]$sSftpScriptRetrieveClose = "quit"
  )

  # System variables...
  [string]$_sSftpScriptLogFile = $sSftpLocalFilePath + "\get-SftpFiles_" + $(get-date -f yyyy-MM-dd) + '.log'
  [string]$_sSftpScriptRetrieveFiles = "lcd " + $sSftpLocalFilePath + "`ncd " + $sSftpRemoteFilePath + "`n" + "ls -1 " + [string]$sSftpRemoteFileMask
  [string]$_sSftpScriptRetrieveOpen = "lcd " + $sSftpLocalFilePath + "`ncd " + $sSftpRemoteFilePath + "`n"
  [string]$_sSftpScriptRetrieveBody = $_sSftpScriptRetrieveOpen
  [string]$_CurrentTimeStamp = $(get-date -f 'yyyy-MM-dd HH:mm:ss')
  [string]$_InfoDoneWithFiles = $_CurrentTimeStamp + " | INFO | Commands executed: "
  [string]$_InfoDoneWithoutFiles = $_CurrentTimeStamp + " | INFO | No remote files found"
  [string]$_Return = $_CurrentTimeStamp + " | ERROR | Unknown Error"

  # Retrieve file list...
  [array]$aFiles = (write-output $_sSftpScriptRetrieveFiles) | sftp -b - -o Port=$sSftpServerPort $sSftpUser@$sSftpServerHost | select-string -notmatch "sftp>"

  # Create script for retrieving files...
  if ($aFiles.length -gt 0) {
    # Create get and rm script lines for every file in the listing...
    for (($n=0); $n -lt $aFiles.length; $n++) { 
      if ($aFiles[$n].line.length -gt 0)
      { 
        $_sSftpScriptRetrieveBody = $_sSftpScriptRetrieveBody + "get " + $aFiles[$n].Line + "`n"
        $_sSftpScriptRetrieveBody = $_sSftpScriptRetrieveBody + "rm " + $aFiles[$n].Line + "`n"
      }
    }

    # Close script file...
    $_sSftpScriptRetrieveBody = $_sSftpScriptRetrieveBody + $sSftpScriptRetrieveClose

    # Process script...
    [array]$aProcess = (write-output $_sSftpScriptRetrieveBody) | sftp -b - -o Port=$sSftpServerPort $sSftpUser@$sSftpServerHost
  
    # Audit log - Commands executed...
    $_InfoDoneWithFiles + $aProcess | Out-File $_sSftpScriptLogFile -Append
    $_Return = $_InfoDoneWithFiles + $aProcess
    [array]$aProcess = ""
  
  } else {
    # Audit log - No remote files...
    $_InfoDoneWithoutFiles | Out-File $_sSftpScriptLogFile -Append
    $_Return = $_InfoDoneWithoutFiles

  }
  return $_Return
}

PS> fnMoveSftpFiles -sSftpServerHost “example.com” -sSftpUser “user” -sSftpRemoteFilePath “/test” -sSftpRemoteFileMask “*.txt” -sSftpLocalFilePath “D:\Tim\Test” [-sSftpServerPort “22“]

PowerShell Validate XML Message

Quick (raw) guide to validate a XML message using Powershell.

# Declare schemas opbject…
$schemas = New-Object System.Xml.Schema.XmlSchemaSet

# Read schema from file…
$schemaItem = Get-Item File.xsd
$fileStream = $schemaItem.OpenRead()
$xsd = [Xml.Schema.XmlSchema]::Read($fileStream, $null)
$fileStream.Close()

# Add XSD to schemas &amp; compile…
$schemas.Add($xsd)
$schemas.Compile()

# Read &amp; validate XML…
[xml]$xml = Get-Content .\File.xml
$xml.Schemas = $schemas
$xml.Validate($null)

Powershell command to generate a new GUID.

[guid]::NewGuid().Guid

PowerShell Cleanup Script

Cleanup logfiles when file change date is older than 30 days…

<#
    Description    : Cleanup logfiles when file change date is older than 30 days...
    Keywords       : Files, Change, Cleanup
    Majorversion   : 1
    Author         : Tim van Kooten Niekerk
    Date           : 2011-11-10
#>

<#      CHANGELOG:
        2013-12-12 => Add Headers (Tim van Kooten Niekerk)
#>

# Global config settings...
[string]$sDirName = "D:\LogFiles\W3SVC705438624"
[string]$sFileNameMask = "*.log"
[string]$sGCIMask = $sDirName + "\" + $sFileNameMask
[string]$sEventLogMessage = "### Logfile cleanup script started ###`r`n"

# Start Main script...
if (Test-Path $sDirName) {
get-childitem $sGCIMask | 
	% { 
		if ($_.LastWriteTime -lt (Get-date).AddDays(-30)) {
		remove-item $_.fullname
		$sEventLogMessage = $sEventLogMessage + "File " + $_.fullname + " (" + $dFileModTime.DateTime + ") removed...`r`n"
		}
	}
}

# Cleanup...
[string]$sEventLogMessage = $sEventLogMessage + "### Logfile cleanup script finished ###"
write-eventLog -LogName "Windows PowerShell" -Source "PowerShell" -EventID 30001 -Message $sEventLogMessage -EntryType Information

GNU/Linux ASCII Table in CSV/TXT format

Simple ASCII table in (formatted) text and available for download in CSV-format

|   | Binary0  | Oct0 | Dec0 | Hex0 | Chr0 |   | Binary3  | Oct3 | Dec3 | Hex3 | Chr3 |   | Binary6  | Oct6 | Dec6 | Hex6 | Chr6 |
| - | -------- | ---- | ---- | ---- | ---- | - | -------- | ---- | ---- | ---- | ---- | - | -------- | ---- | ---- | ---- | ---- |
|   | 00000000 |  000 |   00 |   00 | NUL  |   | 00110000 |  060 |   48 |   30 | 0    |   | 01100000 |  140 |   96 |   60 | `    |
|   | 00000001 |  001 |   01 |   01 | SOH  |   | 00110001 |  061 |   49 |   31 | 1    |   | 01100001 |  141 |   97 |   61 | a    |
|   | 00000010 |  002 |   02 |   02 | STX  |   | 00110010 |  062 |   50 |   32 | 2    |   | 01100010 |  142 |   98 |   62 | b    |
|   | 00000011 |  003 |   03 |   03 | ETX  |   | 00110011 |  063 |   51 |   33 | 3    |   | 01100011 |  143 |   99 |   63 | c    |
|   | 00000100 |  004 |   04 |   04 | EOT  |   | 00110100 |  064 |   52 |   34 | 4    |   | 01100100 |  144 |  100 |   64 | d    |
|   | 00000101 |  005 |   05 |   05 | ENQ  |   | 00110101 |  065 |   53 |   35 | 5    |   | 01100101 |  145 |  101 |   65 | e    |
|   | 00000110 |  006 |   06 |   06 | ACK  |   | 00110110 |  066 |   54 |   36 | 6    |   | 01100110 |  146 |  102 |   66 | f    |
|   | 00000111 |  007 |   07 |   07 | BEL  |   | 00110111 |  067 |   55 |   37 | 7    |   | 01100111 |  147 |  103 |   67 | g    |
|   | 00001000 |  010 |   08 |   08 | BS   |   | 00111000 |  070 |   56 |   38 | 8    |   | 01101000 |  150 |  104 |   68 | h    |
|   | 00001001 |  011 |   09 |   09 | HT   |   | 00111001 |  071 |   57 |   39 | 9    |   | 01101001 |  151 |  105 |   69 | i    |
|   | 00001010 |  012 |   10 |   0A | LF   |   | 00111010 |  072 |   58 |   3A | :    |   | 01101010 |  152 |  106 |   6A | j    |
|   | 00001011 |  013 |   11 |   0B | VT   |   | 00111011 |  073 |   59 |   3B | ;    |   | 01101011 |  153 |  107 |   6B | k    |
|   | 00001100 |  014 |   12 |   0C | FF   |   | 00111100 |  074 |   60 |   3C | <    |   | 01101100 |  154 |  108 |   6C | l    |
|   | 00001101 |  015 |   13 |   0D | CR   |   | 00111101 |  075 |   61 |   3D | =    |   | 01101101 |  155 |  109 |   6D | m    |
|   | 00001110 |  016 |   14 |   0E | SO   |   | 00111110 |  076 |   62 |   3E | >    |   | 01101110 |  156 |  110 |   6E | n    |
|   | 00001111 |  017 |   15 |   0F | SI   |   | 00111111 |  077 |   63 |   3F | ?    |   | 01101111 |  157 |  111 |   6F | o    |
|   | 00010000 |  020 |   16 |   10 | DLE  |   | 01000000 |  100 |   64 |   40 | @    |   | 01110000 |  160 |  112 |   70 | p    |
|   | 00010001 |  021 |   17 |   11 | DC1  |   | 01000001 |  101 |   65 |   41 | A    |   | 01110001 |  161 |  113 |   71 | q    |
|   | 00010010 |  022 |   18 |   12 | DC2  |   | 01000010 |  102 |   66 |   42 | B    |   | 01110010 |  162 |  114 |   72 | r    |
|   | 00010011 |  023 |   19 |   13 | DC3  |   | 01000011 |  103 |   67 |   43 | C    |   | 01110011 |  163 |  115 |   73 | s    |
|   | 00010100 |  024 |   20 |   14 | DC4  |   | 01000100 |  104 |   68 |   44 | D    |   | 01110100 |  164 |  116 |   74 | t    |
|   | 00010101 |  025 |   21 |   15 | NAK  |   | 01000101 |  105 |   69 |   45 | E    |   | 01110101 |  165 |  117 |   75 | u    |
|   | 00010110 |  026 |   22 |   16 | SYN  |   | 01000110 |  106 |   70 |   46 | F    |   | 01110110 |  166 |  118 |   76 | v    |
|   | 00010111 |  027 |   23 |   17 | ETB  |   | 01000111 |  107 |   71 |   47 | G    |   | 01110111 |  167 |  119 |   77 | w    |
|   | 00011000 |  030 |   24 |   18 | CAN  |   | 01001000 |  110 |   72 |   48 | H    |   | 01111000 |  170 |  120 |   78 | x    |
|   | 00011001 |  031 |   25 |   19 | EM   |   | 01001001 |  111 |   73 |   49 | I    |   | 01111001 |  171 |  121 |   79 | y    |
|   | 00011010 |  032 |   26 |   1A | SUB  |   | 01001010 |  112 |   74 |   4A | J    |   | 01111010 |  172 |  122 |   7A | z    |
|   | 00011011 |  033 |   27 |   1B | ESC  |   | 01001011 |  113 |   75 |   4B | K    |   | 01111011 |  173 |  123 |   7B | {    |
|   | 00011100 |  034 |   28 |   1C | FS   |   | 01001100 |  114 |   76 |   4C | L    |   | 01111100 |  174 |  124 |   7C | |    |
|   | 00011101 |  035 |   29 |   1D | GS   |   | 01001101 |  115 |   77 |   4D | M    |   | 01111101 |  175 |  125 |   7D | }    |
|   | 00011110 |  036 |   30 |   1E | RS   |   | 01001110 |  116 |   78 |   4E | N    |   | 01111110 |  176 |  126 |   7E | ~    |
|   | 00011111 |  037 |   31 |   1F | US   |   | 01001111 |  117 |   79 |   4F | O    |   | 01111111 |  177 |  127 |   7F | DEL  |
|   | 00100000 |  040 |   32 |   20 |      |   | 01010000 |  120 |   80 |   50 | P    |   |          |      |      |      |      |
|   | 00100001 |  041 |   33 |   21 | !    |   | 01010001 |  121 |   81 |   51 | Q    |   |          |      |      |      |      |
|   | 00100010 |  042 |   34 |   22 | "    |   | 01010010 |  122 |   82 |   52 | R    |   |          |      |      |      |      |
|   | 00100011 |  043 |   35 |   23 | #    |   | 01010011 |  123 |   83 |   53 | S    |   |          |      |      |      |      |
|   | 00100100 |  044 |   36 |   24 | $    |   | 01010100 |  124 |   84 |   54 | T    |   |          |      |      |      |      |
|   | 00100101 |  045 |   37 |   25 | %    |   | 01010101 |  125 |   85 |   55 | U    |   |          |      |      |      |      |
|   | 00100110 |  046 |   38 |   26 | &    |   | 01010110 |  126 |   86 |   56 | V    |   |          |      |      |      |      |
|   | 00100111 |  047 |   39 |   27 | '    |   | 01010111 |  127 |   87 |   57 | W    |   |          |      |      |      |      |
|   | 00101000 |  050 |   40 |   28 | (    |   | 01011000 |  130 |   88 |   58 | X    |   |          |      |      |      |      |
|   | 00101001 |  051 |   41 |   29 | )    |   | 01011001 |  131 |   89 |   59 | Y    |   |          |      |      |      |      |
|   | 00101010 |  052 |   42 |   2A | *    |   | 01011010 |  132 |   90 |   5A | Z    |   |          |      |      |      |      |
|   | 00101011 |  053 |   43 |   2B | +    |   | 01011011 |  133 |   91 |   5B | [    |   |          |      |      |      |      |
|   | 00101100 |  054 |   44 |   2C | ,    |   | 01011100 |  134 |   92 |   5C | \    |   |          |      |      |      |      |
|   | 00101101 |  055 |   45 |   2D | -    |   | 01011101 |  135 |   93 |   5D | ]    |   |          |      |      |      |      |
|   | 00101110 |  056 |   46 |   2E | .    |   | 01011110 |  136 |   94 |   5E | ^    |   |          |      |      |      |      |
|   | 00101111 |  057 |   47 |   2F | /    |   | 01011111 |  137 |   95 |   5F | _    |   |          |      |      |      |      |

PowerShell Admin Functions (Module)

Some usefull (and less usefull) admin functions…

function fnGetFQDN() {
  param (
	  [switch]$swIsEmail = $false
  )
  $oNETIP = [System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties()
  if ($swIsEmail -eq $true) {
    [string]$Return1 = "noreply@" + $oNETIP.HostName + "." + $oNETIP.DomainName
  } else {
    [string]$Return1 = $oNETIP.HostName + "." + $oNETIP.DomainName
  }  
  return $Return1
}
# Do not forget to register the eventlogsources in windows before you use this function...
function fnWriteEventLog() {
  param (
    [string]$sNode, 
    [string]$sMessage, 
    [string]$sEventLogSource = "DBA",  
    [int]$iEventID = 1001, 
    [string]$sType = "Error"
  )
  if ( ($sNode) -and ($sMessage) ) {
    [string]$sFormatMessage = "Node: " + $sNode + "`r`n`r`n" + $sMessage
    Write-EventLog -LogName Application -Source $sEventLogSource -EntryType $sType -EventID $iEventID -Message $sFormatMessage
  } else {
    return "ERROR: fnWriteEventLog missing arguments..."
  }
}
  
function fnSendMail()
{
  param (
    [string]$sSMTPSrvrName, 
    [string]$sFrom, 
    [string]$sTo, 
    [string]$sSubject, 
    [string]$sBody, 
    [string]$sAttFileName, 
    [switch]$swIsBodyHTML = $false
  )

  if (($sSMTPSrvrName) -and ($sFrom) -and ($sTo) -and $sSubject) {
  
    # Declare mail objects...
    $oMessage = new-object Net.Mail.MailMessage
    $oSMTP = new-object Net.Mail.SmtpClient($sSMTPSrvrName)

    # Pass values to object...
    $oMessage.From = $sFrom
    $oMessage.To.Add($sTo)
    $oMessage.Subject = $sSubject
    $oMessage.IsBodyHtml = $swIsBodyHTML
    $oMessage.BodyEncoding = ([System.Text.Encoding]::UTF8)
    if ($sBody) { $oMessage.Body = $sBody }

    # Add attachment...
    if ($sAttFileName) {
      $oAttachment = new-object Net.Mail.Attachment($sAttFileName)
      $oMessage.Attachments.Add($oAttachment)
    }

    $oSMTP.Send($oMessage)
    if ($? -eq "True") {
      #fnWriteEventLog -sNode (fnGetFQDN) -sMessage "Email has been sent..." -iEventID 1 -sType "Information"
      return "INFO: Email has been sent..." 
    } else {
      fnWriteEventLog -sNode (fnGetFQDN) -sMessage "Error sending mail..." -iEventID 501
      return "ERROR: Error sending e-mail..."
    }

  } else {
    fnWriteEventLog -sNode (fnGetFQDN) -sMessage "fSendMail argument missing..." -iEventID 501
    return "ERROR: Argument(s) missing. [fnSendMail `"SMTPServerName`" `"From`" `"To`" `"Subject`" `"Body`" (`"AttachFileName`" `"isBodyHTML`")]"
  }
}

function fnSQLCmd([string]$sInstance, [string]$sQuery, [string]$sDatabase) {
  # Register SQPPS Module...
  $oSQLPSModule = Get-Module | Where {$_.name -eq "SQLPS" }
  if ($oSQLPSModule.Count -eq 0) {
    Import-Module "SQLPS" -WarningAction SilentlyContinue
  }

  if ($sDatabase) {
    [string]$sQuery = "Invoke-SqlCmd -ServerInstance " + $sInstance + " -Database " + $sDatabase + " -QueryTimeout 30 -Query `"" + $sQuery + "`" ; 
    if (`$? -eq `$false) { @{`"ERROR0`" = `$error[0]}; @{`"ERROR1`" = `$error[1]} }" 
  } else {
    [string]$sQuery = "Invoke-SqlCmd -ServerInstance " + $sInstance + " -QueryTimeout 30 -Query `"" + $sQuery + "`" ; 
    if (`$? -eq `$false) { @{`"ERROR0`" = `$error[0]}; @{`"ERROR1`" = `$error[1]} }" 
  }
  return Invoke-Expression $sQuery
}

function fnTCPSock([string]$sHostName, [string]$sPort, [string]$sScript) {
  # Convert script string to byte for write stream...
  [byte[]]$byteScript = [System.Text.Encoding]::ASCII.GetBytes($($sScript))
  # Open 4096 Bytes buffer for read stream...
  [byte[]]$byteBuffer = New-Object System.Byte[] 16384
  
  # Connect to host...
  $oTCPSock = New-Object System.Net.Sockets.TcpClient($sHostName, $sPort)
  $oStream = $oTCPSock.GetStream() 
  
  # Feed script(byte) tot write stream...
  $oStream.Write($byteScript, 0, $byteScript.Length)

  # Return read buffer converted to string...
  [string]$sCount = $oStream.Read($byteBuffer, 0, 16384)
  return [System.Text.Encoding]::ASCII.GetString($byteBuffer, 0, $sCount) 

  # Close objects...
  $oResult.Close()
  $oSockTCP.Close()
}

function fnSSHCmd()
{
  param (
    [string]$sHostName, 
    [int]$iPort = 22, 
    [string]$sUser, 
    [string]$sKeyFile, 
    [string]$sCommand
  )

  # Register SSH.NET (http://www.powershelladmin.com/wiki/SSH_from_PowerShell_using_the_SSH.NET_library) Library...
  $oSSHModule = Get-Module | Where {$_.name -eq "SSH-Sessions" }
  if ($oSSHModule.Count -eq 0) {
    Import-Module "SSH-Sessions" -WarningAction SilentlyContinue
  }
  
  # Start Session...
  $null = New-SshSession -ComputerName $($sHostName) -Port $($iPort) -Username $($sUser) -KeyFile $($sKeyFile)

  # Execute Command...
  [string]$sSshCmd1 = "Invoke-SshCommand -ComputerName " + $sHostName + " -Quiet -Command " + $sCommand
  [string]$sSshResult1 = Invoke-Expression $sSshCmd1

  # Cleanup and return result...
  $null = Remove-SshSession -ComputerName $($sHostName)
  return $sSshResult1
}

function fnGetSFTPItem()
{
  param (
    [string]$sHostName, 
    [int]$iPort = 22, 
    [string]$sUser, 
    [string]$sKeyFile, 
    [string]$sSourcePath,
    [string]$sDestinationPath,
    [bool]$bDeleteSourceFiles = $false, 
    [string]$sHostKeyFP
  )

  # Load SCP assembly. More info: http://winscp.net/eng/docs/library_powershell
  if (-not (Test-Path 'D:\Tools\WinSCP\WinSCPnet.dll')) {
    throw 'Cannot find WinSCPnet assembly'
  }
  # Import assembly
  [void][System.Reflection.Assembly]::LoadFile('D:\Tools\WinSCP\WinSCPnet.dll')

  # Set connection options...
  $oSFTPSessionOpts = New-Object WinSCP.SessionOptions
  $oSFTPSessionOpts.Protocol = [WinSCP.Protocol]::SFTP
  $oSFTPSessionOpts.HostName = $sHostName
  $oSFTPSessionOpts.PortNumber = $iPort
  $oSFTPSessionOpts.UserName = $sUser
  $oSFTPSessionOpts.SshPrivateKeyPath = $sKeyFile
  if ($sSshHostKeyFP) {
    $oSFTPSessionOpts.SshHostKeyFingerprint = $sSshHostKeyFP
    $oSFTPSessionOpts.GiveUpSecurityAndAcceptAnySshHostKey = 0
  } else {
    $oSFTPSessionOpts.GiveUpSecurityAndAcceptAnySshHostKey = 1
  }
    		
  # Setting transfer options
  $oSFTPTransferOptions = New-Object WinSCP.TransferOptions
  $oSFTPTransferOptions.TransferMode = [WinSCP.TransferMode]::Binary

  # Creating session
  $oSFTPSession = New-Object WinSCP.Session
  $oSFTPSession.Open($oSFTPSessionOpts)

  # Sending files...
  $oTransferResult = $oSFTPSession.GetFiles($sSourcePath, $sDestinationPath, $bDeleteSourceFiles, $oSFTPTransferOptions)
  
  # Cleanup and return result...
  $oSFTPSession.Close()
  $oSFTPSession.Dispose()
  return $oTransferResult
}

function fnGetFTPSItem()
{
  param (
    [string]$sHostName, 
    [int]$iPort = 21, 
    [string]$sUser, 
    [string]$sPassword, 
    [string]$sSourcePath,
    [string]$sDestinationPath,
    [bool]$bDeleteSourceFiles = $false
  )

  # Load SCP assembly. More info: http://winscp.net/eng/docs/library_powershell
  if (-not (Test-Path 'D:\Tools\WinSCP\WinSCPnet.dll')) {
    throw 'Cannot find WinSCPnet assembly'
  }
  # Import assembly
  [void][System.Reflection.Assembly]::LoadFile('D:\Tools\WinSCP\WinSCPnet.dll')

  # Set connection options...
  $oSFTPSessionOpts = New-Object WinSCP.SessionOptions
  $oSFTPSessionOpts.Protocol = [WinSCP.Protocol]::FTP
  $oSFTPSessionOpts.FtpMode = [WinSCP.FtpMode]::passive
  $oSFTPSessionOpts.FtpSecure = [WinSCP.FtpSecure]::explicittls
  $oSFTPSessionOpts.HostName = $sHostName
  $oSFTPSessionOpts.PortNumber = $iPort
  $oSFTPSessionOpts.UserName = $sUser
  $oSFTPSessionOpts.Password = $sPassword
    		
  # Setting transfer options
  $oSFTPTransferOptions = New-Object WinSCP.TransferOptions
  $oSFTPTransferOptions.TransferMode = [WinSCP.TransferMode]::Binary

  # Creating session
  $oSFTPSession = New-Object WinSCP.Session
  $oSFTPSession.Open($oSFTPSessionOpts)

  # Sending files...
  $oTransferResult = $oSFTPSession.GetFiles($sSourcePath, $sDestinationPath, $bDeleteSourceFiles, $oSFTPTransferOptions)
  
  # Cleanup and return result...
  $oSFTPSession.Close()
  $oSFTPSession.Dispose()
  return $oTransferResult
}

GNU/Linux Curl SOAP Request using Mutual SSL

POST a Soap Message using curl using Mutual SSL…

curl -k --cert certchain.pem:password --key server.key \
-d "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:tot=\"http://timvkn.nl/services/testservice\" ><soapenv:Header/><soapenv:Body><tot:getTest><Name>%</Name></tot:getTest></soapenv:Body></soapenv:Envelope>" \
-H 'Content-Type: application/soap+xml' \
-H 'SOAPAction: "http://timvkn.nl/services/testservice/getTest"' \
https://timvkn.nl/testservice/getTest --tlsv1.2 -o result.xml -v