How to replace Invoke-RestMethod into PowerShell 2.0 - powershell

I have created a script in PowerShell 5.1 that retrieves mail messages not older that one day with 'report' as a subject and save their attachments into local drive. The problem is that in the production environment I have only Powershell 2.0. I am using Invoke-RestMethod in my code like this:
$url = "https://outlook.office365.com/api/v1.0/me/messages"
$date = (get-date).AddDays(-1).ToString("yyyy-MM-dd")
$subject = "'report'"
$messageQuery = "" + $url + "?`$select=Id&`$filter=HasAttachments eq true and DateTimeReceived ge " + $date + " and Subject eq " + $subject
$messages = Invoke-RestMethod $messageQuery -Credential $cred
foreach ($message in $messages.value)
{
$query = $url + "/" + $message.Id + "/attachments"
$attachments = Invoke-RestMethod $query -Credential $cred
foreach ($attachment in $attachments.value)
{
$attachment.Name
# SAVE ATTACHMENT CODE HERE
}
}
Is there a simple way to convert the code in order to be suitable for PowerShell 2.0?

Invoke-WebRequest
This command is basically the same as Invoke-RestMethod except in how it handles the data after it receives it. You are going to have to make some small modifications on how you parse your data.
I'll wager you are receiving JSON data so you would just run your Invoke-WebRequest command and pipe it to ConvertFrom-JSON and assign the results to a var. This will let you then do something like $x.messages | % { $_ }
You will need to implement this converter in 2.0. You can copy and paste from: PowerShell 2.0 ConvertFrom-Json and ConvertTo-Json implementation
XML is supported in PS 2.0 natively.

Related

How to make multi-line uri using invoke-webrequest in Powershell

I'm trying to concatenate my uri in this invoke so that I can have each variable on a separate line. That way I can make changes easier and don't have to search as hard. I was able to do this in a bash script, but am at a loss for how to do this in Powershell.
Line as follows:
Invoke-WebRequest -Uri (beginning of url)?date=$date"&"time=$time"&"name=$env:computername"&"loginid=$env:username"&"sn=$serialnumber"&"ipaddr=$ipaddr"&"verb=profileclear
Thanks!
I think the easiest way of achieving this would be like this:
$uri = "Https://something.somewhere/?" +
"date=$date&" +
"time=$time&" +
"name=$env:computername&" +
"loginid=$env:username&" +
"sn=$serialnumber&" +
"ipaddr=$ipaddr&" +
"verb=profileclear"
Invoke-WebRequest -Uri $uri
I would create an array of variable strings, join them, and build a uri:
$variables = "date=$date",
"time=$time",
"name=$env:computername",
"loginid=$env:username",
"sn=$serialnumber",
"ipaddr=$ipaddr",
"verb=profileclear"
$uri = [System.UriBuilder]::new('https://contoso.com')
$uri.Query = $variables -join '&'
Invoke-WebRequest -Uri $uri.ToString()
One option is to store the query parameters in an ordered dictionary and construct the URL from that:
$parameters = [ordered]#{
date = $date
time = $time
name = $env:computername
loginid = $env:username
sn = $serialnumber
ipaddr = $ipaddr
verb = 'profileclear'
}
$baseURI = 'https://host.fqdn/path'
# Construct full URI string from base URI + parameters
$queryString = #($parameters.GetEnumerator() |ForEach-Object {
'{0}={1}' -f $_.Key,$_.Value
}) -join '&'
$URI = '{0}?{1}' -f $baseURI,$queryString
Invoke-WebRequest -Uri $URI

How to escape non-ascii symbols in PowerShell 5.1?

I'm trying to send a file content to server:
$uri = ...
$headers = #{
...
"Content-Type" = "application/json"
}
[string] $content = Get-Content .\filename -Encoding utf8 -Raw
$body = #{
...
"content" = $content
} | ConvertTo-Json
$response = Invoke-WebRequest $uri -Method 'PUT' -Headers $headers -Body $body
But all of non-ascii symbols are changed to another similar symbols or question marks
How can I escape them?
I've read documentation and I know about parameter -EscapeHandling of cmdlet ConvertTo-Json, but it's available from PowerShell 6.2, I have only 5.1
As a result, I wrote a simple function:
function EscapeNonAscii([string] $s)
{
$sb = New-Object System.Text.StringBuilder;
for ([int] $i = 0; $i -lt $s.Length; $i++)
{
$c = $s[$i];
if ($c -gt 127)
{
$sb = $sb.Append("\u").Append(([int] $c).ToString("X").PadLeft(4, "0"));
}
else
{
$sb = $sb.Append($c);
}
}
return $sb.ToString();
}
And used it like this:
$updateFileResponse = Invoke-WebRequest $updateFileUri -Method 'PUT' -Headers $headers -Body (EscapeNonAscii $body)
It helped. For everybody who will google it in the future, it's a request to GitLab API Update existing file in repository
PS: I use PS as C# because I know it badly. If somebody knows how to rewrite this fragment better please let me know.
PPS: And also I know that StringBuilder.Append changes an existing object, but I add here assigning ($sb = $sb.Append($c) instead of simple $sb.Append($c)) because it prints every action to console. If you know how to fix it please let me know.

Email Attachment and Body Naming

I am working on downloading email bodies and their attachments. I want to make sure that each sender has numbers attached to the filename to differentiate from other documents. The counter should start per each sender. For example
Sender1
Sender1-Emailbody-0
Sender1-pdf attachment-1
Sender1-jpg attachment -2
Sender2
Sender2-Emailbody-0
Sender2-pdf attachment -1
Sender2-jpg attachment -2
I am not sure of how to about it. Any help, please. Thanks
$emailQuery1 = $url + "?`$select=Id,Sender,DateTimeReceived&`$filter=HasAttachments eq true and DateTimeReceived ge " + $datetime
$emails = Invoke-RestMethod -Uri $emailQuery1 -Headers $head
## Loop through each results
Foreach ($email in $emails.value)
{
#get attachments and save to file system
$query = $url + "/" + $email.Id + "/attachments"
$body = $url + "/" + $email.Id + "/body"
$receivedtime = "/" + $email.id + "/DateTimeReceived"
$attachments = Invoke-RestMethod -Uri $query -Headers $head
$emailbody = Invoke-RestMethod -Uri $body -Headers $head
Foreach($em in $emailbody)
{
$bodyitems = $em.content
Foreach ($attachment in $attachments.value)
{
$attachment.Name
$path = $DFSPath + $recvtime +"_" + $email.Sender.EmailAddress.Address + "_" + $attachment.Name
$Content = [System.Convert]::FromBase64String($attachment.ContentBytes)
$recvtime = $email.DateTimeReceived | get-date -Format yyyyMMddHHmmss
$bodyitems | out-file -FilePath ($DFSPath +$recvtime +"_" + $email.Sender.EmailAddress.Address`
+"_emailbody-" +$Counter+".html")
Set-Content -Path $path -Value $Content -Encoding Byte
}
}
}
I recommend using a counting variable that gets incremented right before you save the file. Set it to 0 at the beginning of the foreach email loop, $x=0, and then put $x++ right before the Out-File command. You can then append it to the file name when saving the file.

Azure Automation Runbook unable to parse the webhookdata as a JSON object

I am badly struck by this problem. I request you to answer or give a hint. I am running out of options.
I am calling an azure runbook upon high CPU utilization via a WebHook. My problem is inside runbook data is not getting decoded properly. For example, the below line is not printing anything.
Write-Output $WebHookData.RequestHeader
Wheras IF i try to explictly convert the data to JSON, like this
*$WebhookData = ConvertFrom-Json $WebhookData*
then it is a throwing error.
ConvertFrom-Json : Invalid JSON primitive: . At line:6 char:31 +
$WebhookData = $WebhookData | ConvertFrom-Json
By the way, I am trying to use the runbook available on Azure gallery {Vertically scale up an Azure Resource Manager VM with Azure Automation}
My Webhook is called from alert created on VM.
A very strange observation:
Working WebHood Example (found in an example) {"WebhookName":"test1","RequestBody":" [\r\n {\r\n \"Message\": \"Test Message\"\r\n }\r\n****]****"
Not Working(the data sent upon calling runbook from VM):
{"WebhookName":"test2","RequestBody":" {\"schemaId\":\"AzureMonitorMetricAlert\"}}
Thanks
I was getting the same error. From my testing, it appears that when performing a "Test" of the runbook, the Webhook data is received as plain text, but when invoked remotely it comes through already formatted as JSON. Here was my solution to cover both scenarios and so far has been working well...
Param (
[object] $WebhookData
)
# Structure Webhook Input Data
If ($WebhookData.WebhookName) {
$WebhookName = $WebhookData.WebhookName
$WebhookHeaders = $WebhookData.RequestHeader
$WebhookBody = $WebhookData.RequestBody
} ElseIf ($WebhookData) {
$WebhookJSON = ConvertFrom-Json -InputObject $WebhookData
$WebhookName = $WebhookJSON.WebhookName
$WebhookHeaders = $WebhookJSON.RequestHeader
$WebhookBody = $WebhookJSON.RequestBody
} Else {
Write-Error -Message 'Runbook was not started from Webhook' -ErrorAction stop
}
I tried with a webhook, the script Write-Output $WebHookData.RequestHeader should work fine.
And if I use ConvertFrom-Json $WebhookData, I can reproduce your issue, not sure why it occurred, according to the doc, the $WebhookData is also in a JSON format, if it is accepted, you could use ConvertFrom-Json -InputObject $WebhookData.RequestBody, it will work fine.
My runbook:
param
(
[Parameter (Mandatory = $false)]
[object] $WebhookData
)
if ($WebhookData) {
Write-Output $WebhookData.RequestHeader
$Body = ConvertFrom-Json -InputObject $WebhookData.RequestBody
Write-Output $Body
} else
{
Write-Output "Missing information";
exit;
}
The powershell script I used to send a webhook:
$uri = "https://s5events.azure-automation.net/webhooks?token=xxxxxxxxxxxx"
$vms = #(
#{ Name="vm01";ResourceGroup="vm01"},
#{ Name="vm02";ResourceGroup="vm02"}
)
$body = ConvertTo-Json -InputObject $vms
$header = #{ message="StartedbyContoso"}
$response = Invoke-WebRequest -Method Post -Uri $uri -Body $body -Headers $header
$jobid = (ConvertFrom-Json ($response.Content)).jobids[0]
Output:
I had the same problem use following to get webhookdata if using test pane with Alert json as input
if(-Not $WebhookData.RequestBody){
$WebhookData = (ConvertFrom-Json -InputObject $WebhookData)
}
$RequestBody = ConvertFrom-JSON -InputObject $WebhookData.RequestBody

Send Mail with attachment via Powershell Graph API

I'm currently trying to send a mail using an automated Powershell script using the GraphAPI from Microsoft.
Here the full story : I need to check every 15 min the mail received on an Office 365 mailbox, get a specific file attachment (filter by is name), download the file, and re-send it with a new mail.
Everything working but I canno't send the new mail with the attachment ( Works without the attachment).
Here my code :
$date = (get-date).ToUniversalTime().AddMinutes(-15).ToString("yyyy-MM-ddTHH:mm:ssZ")
$Uri = "https://graph.microsoft.com/v1.0/me/messages"
$UriSend = "https://graph.microsoft.com/v1.0/me/sendMail"
$filter = "?`$select=Id,ReceivedDateTime&`$filter=HasAttachments eq true and ReceivedDateTime ge " + $date
$url = $Uri + $filter
$Result = (Invoke-RestMethod -Method Get -Headers $requestheader -Uri $url)
if($Result.value){
## Loop through each results
foreach ($message in $Result.value)
{
# get attachments and save to file system
$query = $Uri + "/" + $message.Id + "/attachments"
$attachments = (Invoke-RestMethod -Method Get -Headers $requestheader -Uri $query)
# in case of multiple attachments in email
foreach ($attachment in $attachments.value)
{
$patternPDF = "FAX AR document\.pdf$"
if($attachment.Name -match $patternPDF)
{
$name = $message.ReceivedDateTime -replace "T","-"
$name = $name -replace "Z",""
$name = $name -replace ":","-"
$path = "c:\Temp\" + $name + ".pdf"
# Creation of the PDF file
$Content = [System.Convert]::FromBase64String($attachment.ContentBytes)
Set-Content -Path $path -Value $Content -Encoding Byte
$file = Get-Content $path -Encoding Byte -ReadCount 0
#Send File by Mail
$body =
#"
{
"message" : {
"subject": "AR Fax",
"body" : {
"contentType": "Text",
"content": "Accusé Fax"
},
"toRecipients": [
{
"emailAddress" : {
"address" : "mail#domain.com"
}
}
],
"attachments":[
{
"##odata.type":"#microsoft.graph.fileAttachment",
"name":"Fax_AR.pdf",
"contentType":"application/pdf",
"contentBytes":"$file"
}
]
},
"saveToSentItems": "true"
}
"#
# Invokes the request
Invoke-RestMethod -Headers $requestheader -Uri $uriSend -Method Post -Body $body
I'm not very good in powershell (or in code generally) so please be indulgent^^
EDIT : I've find another way to do what i want (I print the file now)
I've find another way to do what i want (I print the file now)
So I'm closing the topic.