Saving Video Data To File From POST request InputStream in PowerShell - powershell

I am having trouble quite figuring out how to save video data sent to me via a HttpListener in PowerShell. I have the following which I believe is just sending it back to the requester but I'm having trouble just saving it into an MP4 file.
$req = $request
$body = $req.InputStream
$reader = New-Object System.IO.StreamReader ($body, $req.ContentEncoding)
$msg = $reader.ReadToEnd()
$reader.Close()
[byte[]] $buffer = [System.Text.Encoding]::UTF8.GetBytes($msg)
$res.ContentLength64 = $buffer.Length
$res.StatusCode = 200
$res.OutputStream.Write($buffer, 0, $buffer.Length)
$res.Close()
Thank you for your time eveyrone!
Update:
I have been able to make files with this, though for some reason in examples they're using 8192 sized byte but PowerShell says it's too big. With this I get zero length files, no errors that I can tell.
$path = "c:\matthew3.mp4"
$file = New-Object System.IO.FileStream $path,CreateNew
[byte]$bytes = 255
[int]$bytes_read = 0
while ( $bytes_read = $request.InputStream.Read($bytes, 0, $bytes.length) > 0 )
{
$file.Write($bytes, 0, $bytes_read)
}
Actually I did get an error:
Exception calling "GetBytes" with "1" argument(s): "Array cannot be null.
Parameter name: chars"
At line:45 char:1
+ $buffer = [System.Text.Encoding]::UTF8.GetBytes($content)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentNullException
Exception calling "Write" with "3" argument(s): "Value cannot be null.
Parameter name: buffer"
At line:47 char:1
+ $response.OutputStream.Write($buffer, 0, $buffer.Length)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentNullException

So the main developer for our company Nick pointed me in the right direction here.
The main thing is that for the FileStream object I needed to add the Write flag, and use the CopyTo method on the InputStream and then close both of them:
$file = New-Object System.IO.FileStream $path,CreateNew,Write
$context.Request.InputStream.CopyTo($file)
$file.Close()
$context.Request.InputStream.Close()

Related

"Invalid URI: The hostname could not be parsed" + "The requested URI is invalid for this FTP command" when downloading using WebClient in PowerShell

I am trying to connect one FTP server using PowerShell like below.
$line = 'MilanRamani.json'
$file = "C:\brivo\json\" + $line
$ftpuri = "ftp://theflowregister\selfregisterflow:Buter239##waws-prod-am2-555.ftp.azurewebsites.windows.net/site/wwwroot/json/" + $line
$webclient = New-Object System.Net.WebClient
$uri = New-Object System.Uri($ftpuri)
$webclient.DownloadFile($uri,$file)
$webclient.Dispose()
Where theflowregister\selfregisterflow is a username, Buter239# is password, waws-prod-am2-555.ftp.azurewebsites.windows.net/site/wwwroot is host and json/ is subfolder.
I am trying to copy one file named MilanRamani.json from FTP and download it at a particular location in the system. but I am getting this error when I execute the above code.
New-Object : Exception calling ".ctor" with "1" argument(s): "Invalid URI: The hostname could not be parsed."
At line:5 char:8
+ $uri = New-Object System.Uri($ftpuri)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [New-Object], MethodInvocationException
+ FullyQualifiedErrorId :
ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
Exception calling "DownloadFile" with "2" argument(s): "The requested URI is invalid for this
FTP command."
At line:6 char:1
+ $webclient.DownloadFile($uri,$file)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : WebException
The # (hash/number sign) has special meaning in URL. If you want to use it explicitly, you have to URL-encode it to %23. You might also have to URL-encode the \ (backslash) as %5C. In general, you can use Uri.EscapeDataString to encode the credentials (and also the filename):
$ftpuri =
"ftp://" +
[Uri]::EscapeDataString("theflowregister\selfregisterflow") + ":" +
[Uri]::EscapeDataString("Buter239#") +
"#waws-prod-am2-555.ftp.azurewebsites.windows.net/site/wwwroot/json/" +
[Uri]::EscapeDataString($line)
An alternative and safer approach is to set the credentials via WebClient.Credentials property, instead of the URL:
$ftpuri =
"ftp://waws-prod-am2-555.ftp.azurewebsites.windows.net/site/wwwroot/json/" +
[Uri]::EscapeDataString($line)
$uri = New-Object System.Uri($ftpuri)
$webclient = New-Object System.Net.WebClient
$webclient.Credentials =
New-Object System.Net.NetworkCredential(
"theflowregister\selfregisterflow", "Buter239#")

Powershell won't read header text in word documents?

I am in need of checkingh a larger number of word documents (doc & docx) for a specific text and found a great tutorial and script by the Scripting Guys;
https://blogs.technet.microsoft.com/heyscriptingguy/2012/08/01/find-all-word-documents-that-contain-a-specific-phrase/
The script reads all documents in a directory and gives the following output;
Number of times mentioned
Total word count in all documents where the specific text is found
The directory of all files containing the specific text.
This is all I need, however their code doesn't seem to actually check the headers of any document, which incidentally is where the specific text I'm looking for is located. Any tips & tricks in making the script read header text would make me very happy.
An alternative solution might be to remove the formatting so that the header text becomes part of the rest of the document? Is this possible?
Edit: Forgot to link the script:
[cmdletBinding()]
Param(
$Path = "C:\Users\use\Desktop\"
) #end param
$matchCase = $false
$matchWholeWord = $true
$matchWildCards = $false
$matchSoundsLike = $false
$matchAllWordForms = $false
$forward = $true
$wrap = 1
$application = New-Object -comobject word.application
$application.visible = $False
$docs = Get-childitem -path $Path -Recurse -Include *.docx
$findText = "specific text"
$i = 1
$totalwords = 0
$totaldocs = 0
Foreach ($doc in $docs)
{
Write-Progress -Activity "Processing files" -status "Processing $($doc.FullName)" -PercentComplete ($i /$docs.Count * 100)
$document = $application.documents.open($doc.FullName)
$range = $document.content
$null = $range.movestart()
$wordFound = $range.find.execute($findText,$matchCase,
$matchWholeWord,$matchWildCards,$matchSoundsLike,
$matchAllWordForms,$forward,$wrap)
if($wordFound)
{
$doc.fullname
$document.Words.count
$totaldocs ++
$totalwords += $document.Words.count
} #end if $wordFound
$document.close()
$i++
} #end foreach $doc
$application.quit()
"There are $totaldocs and $($totalwords.tostring('N')) words"
#clean up stuff
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($range) | Out-Null
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($document) | Out-Null
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($application) | Out-Null
Remove-Variable -Name application
[gc]::collect()
[gc]::WaitForPendingFinalizers()
EDIT 2: My colleague got the idea to call on the section header instead;
Foreach ($doc in $docs)
{
Write-Progress -Activity "Processing files" -status "Processing $($doc.FullName)" -PercentComplete ($i /$docs.Count * 100)
$document = $application.documents.open($doc.FullName)
# Load first section of the document
$section = $doc.sections.item(1);
# Load header
$header = $section.headers.Item(1);
# Set the range to be searched to only Header
$range = $header.content
$null = $range.movestart()
$wordFound = $range.find.execute($findText,$matchCase,
$matchWholeWord,$matchWildCards,$matchSoundsLike,
$matchAllWordForms,$forward,$wrap,$Format)
if($wordFound) [script continues as above]
But this is met with the following errors:
You cannot call a method on a null-valued expression.
At C:\Users\user\Desktop\count_mod.ps1:27 char:31
+ $section = $doc.sections.item <<<< (1);
+ CategoryInfo : InvalidOperation: (item:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
You cannot call a method on a null-valued expression.
At C:\Users\user\Desktop\count_mod.ps1:29 char:33
+ $header = $section.headers.Item <<<< (1);
+ CategoryInfo : InvalidOperation: (Item:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
You cannot call a method on a null-valued expression.
At C:\Users\user\Desktop\count_mod.ps1:33 char:26
+ $null = $range.movestart <<<< ()
+ CategoryInfo : InvalidOperation: (movestart:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
You cannot call a method on a null-valued expression.
At C:\Users\user\Desktop\count_mod.ps1:35 char:34
+ $wordFound = $range.find.execute <<<< ($findText,$matchCase,
+ CategoryInfo : InvalidOperation: (execute:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Is this the right way to go or is it a dead end?
if you want the header text, you can try the following:
$document.content.Sections.First.Headers.Item(1).range.text
For anyone looking at this question in the future: Something isn't quite working with my code above. It seems to return a false positive and puts $wordFound = 1 regardless of the content of the document thus listing all documents found under $path.
Editing the variables within Find.Execute doesn't seem to change the outcome of $wordFound. I believe the problem might be found in my $range, as it is the only place I get errors in while going through the code step by step.
Errors listed;
You cannot call a method on a null-valued expression.
At C:\Users\user\Desktop\Powershell\count.ps1:24 char:58
+ $range = $document.content.Structures.First.Headers.Item <<<< (1).range.Text
+ CategoryInfo : InvalidOperation: (Item:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Exception calling "MoveStart" with "0" argument(s): "The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)"
At C:\Users\user\Desktop\Powershell\count.ps1:25 char:26
+ $null = $range.MoveStart <<<< ()
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ComMethodCOMException
You cannot call a method on a null-valued expression.
At C:\Users\user\Desktop\Powershell\count.ps1:26 char:34
+ $wordFound = $range.Find.Execute <<<< ($findText,$matchCase,
+ CategoryInfo : InvalidOperation: (Execute:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull

Powershell compare size of local file to file on sharepoint

I am using the current code to download a file from a sharepoint...
$webClient = New-Object System.Net.WebClient
$webClient.UseDefaultCredentials = $true
$webClient.DownloadFile($sharepointPathFile, $localPathFile) | Out-Null
But what if I wanted to check if the file is already at the local location and the size matches or is different? How would I do this using powershell?
Update
This was the closest I could get...
$url = $sharepointPathFile
$clnt = [System.Net.WebRequest]::Create($url)
$resp = $clnt.GetResponse()
$fileSize = $resp.ContentLength
Write-Host $fileSize
But I am getting the following error:
Exception calling "GetResponse" with "0" argument(s): "The remote server returned an error: (401) Unauthorized."
At C:\Scripts\Tests\testCheckUpdatedSearchFiles.ps1:345 char:2
+ $resp = $clnt.GetResponse()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : WebException
I have full read and download rights, so is there something else not going right here?
I'm not sure if the "GetResponse" method will return exactly what you're looking for. And depending on the ContentLength, you may want to explicitly define your types. I would try something like this:
$webClient = New-Object System.Net.WebClient
$webClient.OpenRead("path/to/file")
[Int64]$fileSize = $webClient.ResponseHeaders["Content-Length"]
Write-Host $fileSize

Using CreateDecryotor() in PowerShell

I was wondering if anyone could help me out with an error I am getting in PowerShell. I am having no issue with creating the encryptor shown below:
$Crypto = New-Object System.Security.Cryptography.RNGCryptoServiceProvider
$IV = New-Object System.Byte[] 16
$Crypto.GetNonZeroBytes($iv)
$RIJSym = new-Object System.Security.Cryptography.RijndaelManaged
[byte[]] $Key = ('mysecret$%#').ToCharArray()
$Encryptor = $RIJSym.CreateEncryptor($Key,$IV)
But for what ever reason I am having an issue when I want to decrypt my key, here is what I am using and the error I get when the Program runs:
$Decrypted = $RIJSym.CreateDecryptor($Encryptor)
Error Message
Cannot find an overload for "CreateDecryptor" and the argument count: "1".
At line:15 char:1
+ $DeCryp = $rijSym.CreateDecryptor($encryptor)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
The error says it all... CreateDecryptor() doesn't have an overload the uses onl a single argument. The valid overloads are:
PS > $RIJSym.CreateDecryptor
OverloadDefinitions
-------------------
System.Security.Cryptography.ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV)
System.Security.Cryptography.ICryptoTransform CreateDecryptor()
You need to create the decryptor the same way you created the encrypter: by specifying the key and IV. Ex.
$Decrypted = $RIJSym.CreateDecryptor($Key, $IV)

Powershell - simply checking if a function completed successfully or not (times out)

I basically have this simple powershell script that executes an ssrs report url and saves it to the network.
It usually runs fine, but sometimes it times out and when it does, it still says it succeeded. I've tried a handful of things with no luck.
A simplified version of my script looks like this:
-----------------------------
function RunReport($url,$outputfile) {
# // create a request
[Net.HttpWebRequest] $req = [Net.WebRequest]::create($url)
$req.Method = "GET"
$req.Timeout = 600000 # = 10 minutes
# // Set credentials
$req.UseDefaultCredentials = $true
#echo "Getting Response"
[Net.HttpWebResponse] $result = $req.GetResponse()
[IO.Stream] $stream = $result.GetResponseStream()
#[IO.StreamReader] $reader = New-Object IO.StreamReader($stream)
[System.IO.FileStream]$writeStream = New-Object System.IO.FileStream($outputfile, [System.IO.FileMode]::Create);
# // write to file
[byte[]]$buffer = new-object byte[] 4096
[int]$total = [int]$count = 0
do
{
$count = $stream.Read($buffer, 0, $buffer.Length)
$writeStream.Write($buffer, 0, $count)
} while ($count -gt 0)
$writeStream.Close()
#$stream.flush()
$stream.Close()
}
$url=...
$outputfile=...
IF(RunReport "$url" "$outputfile")
{Write-Host "Success"}
ELSE
{Write-Host "Failed"}
-------------------------------
I've tried stuff like this with no luck:
RunReport "$url" "$outputfile"
If($?)
{Write-Host "Success"}
ELSE
{Write-Host "Failed"}
and
RunReport "$url" "$outputfile"
If($? -eq true)
{Write-Host "Success"}
ELSE
{Write-Host "Failed"}
The timeout error I'm dealing with is:
Exception calling "GetResponse" with "0" argument(s): "The operation has timed out"
At C:\data\powershell\script.ps1:9 char:49
+ [Net.HttpWebResponse] $result = $req.GetResponse <<<< ()
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
You cannot call a method on a null-valued expression.
At C:\data\powershell\script.ps1:10 char:48
+ [IO.Stream] $stream = $result.GetResponseStream <<<< ()
+ CategoryInfo : InvalidOperation: (GetResponseStream:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
You cannot call a method on a null-valued expression.
At C:\data\powershell\script.ps1:18 char:38
+ $count = $stream.Read <<<< ($buffer, 0, $buffer.Length)
+ CategoryInfo : InvalidOperation: (Read:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
You cannot call a method on a null-valued expression.
At C:\data\powershell\script.ps1:23 char:14
+ $stream.Close <<<< ()
+ CategoryInfo : InvalidOperation: (Close:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Any help would be greatly appreciated. I assume this should be fairly easy, just don't have the correct syntax ? Thanks
Maybe you can use try/catch to deal with that part like this:
try {
[Net.HttpWebResponse] $result = $req.GetResponse()
}
catch {
return 1
}
You can apply the same technique in other places where you suspect code is not doing what it is supposed to do like:
try {
[System.IO.FileStream]$writeStream = New-Object System.IO.FileStream($outputfile, [System.IO.FileMode]::Create);
}
catch {
return 1
}
Once you detect where the issue is happening, you could then look into exception like
catch { write-warning $_ ; exit 1 }
The 'cannot call a method on a null-valued expression' errors are all stemming from the fact that the .GetResponse method is failing with a timeout, leaving the $result variable unassigned. The simplest change would be to put the rest of the script (after "$result = $req.GetResponse()") into an "if ($result) {}" block. You can then use a "then {}" block to do your error handling.
A more advanced method would be to use try {} and catch {} blocks, to catch the actual timeout exception and handle it properly.
You have two problems:
The timeouts (and the cascading errors from that)
Your RunReport function doesn't ever return anything.
For #2, you can't test something that doesn't exist. So make your function return some kind of success/fail indicator to the caller.
For #1, when you call GetResponse() you need to wrap it in a try/catch block, catch the exception, and exit the function with the appropriate status returned to the caller.
You might want to look at this SO post about calling SSRS using SOAP methods as well.