Articles‎ > ‎Homemade Software‎ > ‎

PowerShell

I find I'm using PowerShell more and more often, but I still need to look up examples.

On this page I have the scripts I've used in the past to refresh my memory.

 
Merge hyper-v drive snapshots, one by one:
PS C:\Hyper-V\Virtual hard disks> function fakemerge { Param ([string]$targetpath);$targetvhd=Get-VHD -Path "$targetpath";$parentpath=$targetvhd.ParentPath;Write-Host "Merge: Merge-VHD -Path" $targetpath "-DestinationPath" $parentpath "-ErrorAction Stop";st
art-sleep -s 3;if ($parentpath){fakemerge "$parentpath"}else{Write-Host "No parent path for $targetpath"} };fakemerge "C:\hyper-v\Virtual Hard Disks\nameserver-drivename-datatype_EE77DAC6-B30D-40B0-BB8D-F719993EEE84.avhdx

Set DNS servers
PS C:\> Set-DnsClientServerAddress -InterfaceIndex 23 -ServerAddresses ("10.168.1.5","10.168.1.15")

Remove a file
PS C:\> Get-ADComputer -Filter *|Select-Object -ExpandProperty name|foreach { Write-Output "$_"; if(Test-Connection -ComputerName $_ -BufferSize 16 -Count 1 ){ Invoke-Command -Script {if (Test-Path '\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp\StupidToHaveHereAnyway.lnk'){remove-item '\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp\StupidToHaveHereAnyway.lnk'}} -ComputerName $_}}
 
Enable a Hyper-V virtual adapter
PS C:\> GET-VM | GET-VMNetworkAdapter | Connect-VMNetworkAdapter –Switchname ‘New-cool-Hyper-V-Lan’ 
 

Add a registry entry to trust a local domain
$UserRegPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains"

#Value 1 = Intranet
$DWord = 1

$Name = "phantomcode.org"
if (-Not (Test-Path "$UserRegPath\$Name")){
 New-Item -Path "$UserRegPath" -ItemType File -Name "$Name"
}
Set-ItemProperty -Path "$UserRegPath\$Name" -Name "http" -Value $DWord
Set-ItemProperty -Path "$UserRegPath\$Name" -Name "https" -Value $DWord
Set-ItemProperty -Path "$UserRegPath\$Name" -Name "*" -Value $DWord


Watch a text file for changes
PS C:\> get-content -tail 10 -wait '\\server\c$\temp\serversmonitored.log'


Use SFTP/SSH/SCP with Posh-SSH module:
PS C:\> Install-Module -Name Posh-ssh
Interactive approvals later:
PS C:\> $username = 'whateveruser'
PS C:\> $password = ConvertTo-SecureString 'WhateverPassword' -AsPlainText -Force
PS C:\> $mycredentials = New-Object System.Management.Automation.PSCredential($username,$password)
PS C:\> New-SSHSession -computername 'whateverserver.example.org' -Credential $mycredentials -Verbose
Or generate an OpenSSH public/private key pair with no password, some notes:
  1. Keep this very secure
  2. I used Putty's too PuTTYgen, rsa and exported OpenSSH key files
  3. Be careful to select the entirety of the public key text as it may not all be visible
PS C:\> $username = 'whateveruser'
PS C:\> $nopassword = new-object System.Security.Securestring
PS C:\> $mycredentials = New-Object System.Management.Automation.PSCredential($username,$nopassword)
PS C:\> New-SSHSession -computername 'whateverserver.example.org' -Credential $mycredentials -KeyFile C:\temp\id_rsa.private -Verbose
Other command examples:
PS C:\> Get-SSHSession | fl
PS C:\> Invoke-SSHCommand -Index 0 -Command "uname -a"
PS C:\> Remove-SSHSession -Index 0 -Verbose
PS C:\> New-SFTPSession -ComputerName 'whateverserver.example.org' -Credential (Get-Credential root) -Verbose | fl
PS C:\> Set-SFTPDirectoryPath -Index 0 -Path /usr/bin
PS C:\> Get-SFTPDirectoryList -Index 0 -Path /tmp
Other commands:
Get-SFTPFile
Move-SFTPFile
Remove-SFTPFile
Set-SFTPFile (Uploads a file)
New-SFTPDirectory
Remove-SFTPDirectory

Use SFTP/FTP/SCP/FTPS with WinSCP module:
PS C:\temp> Install-Module -Name WinSCP
Interactive approvals later:
PS C:\> $sessionOption = New-WinSCPSessionOption -hostname 'whateverserver' -Protocol 'Sftp'
PS C:\> $sshHostKeyFingerprint = Get-WinSCPHostKeyFingerprint -SessionOption $sessionOption
PS C:\> $cred = Get-Credential
PS C:\> $sessionOption = New-WinSCPSessionOption -hostname 'whateverserver' -Protocol 'Sftp' -Credential $cred -SshHostKeyFingerprint $sshHostKeyFingerprint
PS C:\> $session1 = New-WinSCPSession -SessionOption $sessionOption
PS C:\> Get-WinSCPChildItem -Path '/home/netadmin'|fl
PS C:\> Remove-WinSCPSession $session1

Logging into a webpage and pulling a download file
<#example_pull.ps1
2018-11-08 Boyce Crownover webmaster@phantomcode.com: created to pull a CSV download
           This was rather tricky because I couldn't get the fine grain control I wanted from the normal tools like WebRequest and WebClient.
   I needed to load a page to get the session cookie, then submit data with POST (including that session cookie) from an image input.
   Then after a successful login, I needed to go to another page, still with the session cookie, and from that page click another
   image input button which results in a stream of data which is the CSV data I'm actually after.
#>

$url = "https://www.example.com/URL/URL/Login.asp"

#Load initial page to get the session cookie
$request = [System.Net.WebRequest]::Create($url)
$request.CookieContainer = New-Object System.Net.CookieContainer
$request.Method="Get"
$response = $request.GetResponse()
$requestStream = $response.GetResponseStream()
$readStream = New-Object System.IO.StreamReader $requestStream
$data=$readStream.ReadToEnd()

 
#Looping seems like it should be unnecessary, but normal pages 
#may have multiple cookies. In this case, I just needed the one.
foreach ($cook in $Response.Cookies)    {
 $lastcookie=$cook.toString()
}
#write-output "Last cookie: $lastcookie" 

#Now that we have the cookie, we post the login data back to the same page.
#I found Telerik Fiddler to be very handy for figuring out exactly what 
#my normal session was doing.
$url = "https://www.example.com/URL/URL/Login.asp"
$postData = "Name=myusername&Password=mypassword&loginButton.x=0&loginButton.y=0"
$buffer = [text.encoding]::ascii.getbytes($postData)
[net.httpWebRequest] $req = [net.webRequest]::create($url)
$req.method = "POST"
$req.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
$req.Headers.Add("Accept-Language: en-US")
$req.Headers.Add("Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7")
$req.Headers.Add("Cookie",$lastcookie)
$req.AllowAutoRedirect = $false
$req.ContentType = "application/x-www-form-urlencoded"
$req.ContentLength = $buffer.length
$req.TimeOut = 50000
$req.KeepAlive = $true
$req.Headers.Add("Keep-Alive: 300");
$reqst = $req.getRequestStream()
$reqst.write($buffer, 0, $buffer.length)
$reqst.flush()
$reqst.close()
[net.httpWebResponse] $res = $req.getResponse()
$resst = $res.getResponseStream()
$sr = new-object IO.StreamReader($resst)
$result = $sr.ReadToEnd()
$res.close()
#$result
#The result is a 302 redirect, which means our session is now successfully authenticated

#Ignoring the redirect, we now go to the download page where we send input
#as if we'd clicked the "Download" button, which isn't an HTML button but an
#input image. As before, Fiddler came in handy.
$url = "https://www.example.com/URL/URL/PageWithDownloadButton.asp"
$postData="downloadButton.x=0&downloadButton.y=0"
$buffer = [text.encoding]::ascii.getbytes($postData)
[net.httpWebRequest] $req = [net.webRequest]::create($url)
$req.method = "POST"
$req.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
$req.Headers.Add("Accept-Language: en-US")
$req.Headers.Add("Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7")
$req.Headers.Add("Cookie",$lastcookie)
$req.AllowAutoRedirect = $false
$req.ContentType = "application/x-www-form-urlencoded"
$req.ContentLength = $buffer.length
$req.TimeOut = 50000
$req.KeepAlive = $true
$req.Headers.Add("Keep-Alive: 300");
$reqst = $req.getRequestStream()
$reqst.write($buffer, 0, $buffer.length)
$reqst.flush()
$reqst.close()
[net.httpWebResponse] $res = $req.getResponse()
$resst = $res.getResponseStream()
$sr = new-object IO.StreamReader($resst)
$result = $sr.ReadToEnd()
$res.close()
Out-File -InputObject $result -FilePath 'result.csv'
#The resulting stream of data is a CSV file that I need for other tasks.


<#REFERENCE 

REFERENCE CODE (UNUSED)
$cc = new-object Net.CookieContainer
$req = [Net.WebRequest]::Create("https://www.example.com/service")
$req.CookieContainer = $cc
$req = [System.Net.HttpWebRequest] [System.Net.WebRequest]::Create($url)
$probe = $html.ReadToEnd() 
$cookie = $ResponseObject.Headers["Set-Cookie"]
$strt = $cookie .indexOf(';', 0)
$sessionid= $cookie.Substring(0,$strt)
$cookie= $data.Headers["Set-Cookie"]
$req.Headers.Add("Accept-Encoding: gzip,deflate")

"Cookie:"
"{0} = {1}"    -f $cook.Name, $cook.Value
"Domain      : {0}"     -f $cook.Domain
"Path        : {0}"     -f $cook.Path
"Port        : {0}"     -f $cook.Port
"Secure      : {0}"     -f $cook.Secure
"When issued : {0}"     -f $cook.TimeStamp
"Expires     : {0}"     -f $cook.expireds
"Expired?    : {0}"     -f $cook.expired
"Don't save  : {0}"     -f $cook.Discard
"Comment     : {0}"     -f $cook.Comment
"Uri for comments: {0}" -f $cook.CommentUri
"Version     : {0}"     -f $cook.Version
"String: {0} :"         -f $cook.ToString()


$data
 Print number of cookies
if ($response.Cookies.Count -gt 0) {
"{0} Cookies returned from: {1}" -f $Response.Cookies.Count,$site
""
}

REFERENCE URLS
#https://stackoverflow.com/questions/34422255/trying-to-do-a-simple-post-request-in-powershell-v2-0-no-luck
#https://stackoverflow.com/questions/5470474/powershell-httpwebrequest-get-method-cookiecontainer-problem
#https://social.microsoft.com/Forums/en-US/837b0841-f878-498d-a830-7462bf879b4a/powershell-post-method-server-not-accepting-the-cookie?forum=Offtopic
#http://eddiejackson.net/data/powershell/Get-Cookie.ps1



Then there was this bit. I found I could do everything I wanted to all the way through clicking the download
button by launching an Internet Explorer object. This can even be hidden. However, I found there was no
way to click the Save button of Internet Exporer without isolating the object, bringing the window to the active
or foreground state, then using sendkeys to send specific keys to the window. Since I want this task to run 
even when nobody is logged into Windows, I don't trust that window manipulation would work and sendkeys is a
little dangerous as I've learned in past programming. That said, it did prove useful to have a program I could run
to record activity to Fiddler without having to do interactive typing, so I'll leave that script here in the reference
notes.

#https://westerndevs.com/simple-powershell-automation-browser-based-tasks/
$loginurl="https://www.example.com/URL/URL/Login.asp"
$membrurl="https://www.example.com/URL/URL/PageWithDownloadButton.asp"
$myusername="myusername"
$mypassword="mypassword"

$ie = new-object -ComObject "InternetExplorer.Application"
$ie.visible = $true #Do you want to see IE?
$ie.silent = $true #Do you want pop-up dialogs suppressed?

$ie.navigate($loginurl)
while($ie.Busy) { Start-Sleep -Milliseconds 2000 } #My example was something like 100... I had to increase it a LOT before it worked

$elements=$ie.Document.IHTMLDocument3_getElementsByName("txtLoginName");foreach ($element in $elements){ $element.value=$myusername }
$elements=$ie.Document.IHTMLDocument3_getElementsByName("txtPassword");foreach ($element in $elements){ $element.value=$mypassword }
$elements=$ie.Document.IHTMLDocument3_getElementsByName("btnLogin");foreach ($element in $elements){ $element.click() }

$ie.navigate($membrurl)
while($ie.Busy) { Start-Sleep -Milliseconds 2000 }

$elements=$ie.Document.IHTMLDocument3_getElementsByName("btnDownload");foreach ($element in $elements){ $element.click() }

while($ie.Busy) { Start-Sleep -Milliseconds 2000 }

#Hit "S" on the keyboard to hit the "Save" button on the download box
$obj = new-object -com WScript.Shell
$obj.AppActivate('Internet Explorer')
$obj.SendKeys('s')



#>



 

Other stuff:
  • https://stackoverflow.com/questions/38732025/upload-file-to-sftp-using-powershell
    • Find-Module "Posh-SSH" |install-module
  • netsh interface ipv4 set address name="Wi-Fi" static 192.168.3.8 255.255.255.0 192.168.3.1
    netsh interface ipv4 set dns name="Wi-Fi" static 8.8.8.8
    netsh interface ipv4 set dns name="YOUR INTERFACE NAME" static DNS_SERVER index=2

Comments