Output in a different format - powershell

I'm hitting an API endpoint for the UniFi Controller.
I run a command to give me devices that do NOT have a specific MAC address.
The command returns 3 mac addresses.
When working with PowerShell, how can you use the 3 mac addresses returned as 3 different items so that I can do a 'foreach' statement on them?
$returnedDevices = $response.data | select mac | where-object {$_.mac -notlike "18:e8:29:4f:0b:33"}
This is what is returned:
mac
---
80:2a:a8:c9:c3:c3
18:e8:29:93:00:d1
18:e8:29:93:6c:85
When I run: $returnedDevices.Count
I get '3'.
So it looks like 3 different values, but if I try to use this in a ForEach statement:
ForEach ($item in $returnedDevices) {
$command = "`{`"cmd`":`"restart`",`"reboot_type`":`"soft`"`,`"mac`":`"$item.mac`"`}"
$response = Invoke-RestMethod -Uri "$devURI" -Method Post -Body $command -ContentType "application/json" -WebSession $session
}
What happens is I get an error because this is what is being sent to the API:
{"cmd":"restart","reboot_type":"soft","mac":"#{mac=80:2a:a8:c9:c3:c3}.mac"}
I would think, it should be:
{"cmd":"restart","reboot_type":"soft","mac":"80:2a:a8:c9:c3:c3}.mac"}
How can I either trim the beginning or, better yet, get the right format?
Also, if I do the following, the output looks like what I would expect:
$item.mac
Output:
80:2a:a8:c9:c3:c3
Thank you,

When you write a variable and its property inside of a string, that property becomes part of the quoted string.
$command = "`{`"cmd`":`"restart`",`"reboot_type`":`"soft`"`,`"mac`":`"$item.mac`"`}"
# vs
$command = "`{`"cmd`":`"restart`",`"reboot_type`":`"soft`"`,`"mac`":`"$($item.mac)`"`}"
1st Command is going to display $item but consider .mac to be part of the regular string. If you need to get the mac out of the variable $item and display it, you have to use the whole thing as a variable... and thats by encapsulating them with $().

Related

Compare-Object API response with text file shows everything is different

I have a Web API that returns an HTML string which I want to compare with a html file on my local machine.
To do so, I have the following code
$Result = (Invoke-WebRequest `
-Uri "{uri}" `
-Headers #{"some-header", "some-value"}).Content
$TestContent = Get-Content -Path ($RepositoryLocation + "index.html") -Raw
$Equal = Compare-Object -ReferenceObject $TestContent -DifferenceObject $Result
When I now use Write-Hosts $Equal it displays me that the whole content is different
When I use Write-Host $Equal.SideIndicator it displays me => <= which also indicates that the complete file is different
Furthermore, using the command with -IncludeEqual -ExcludeDifferent displays empty result, so like I said, no lines are the same.
So what I tried next was to save the Content of $Result into a text file and compare them then, but still, it told me, that the whole file is different.
I then used diffchecker.com as well as JetBrains IDEs integrated comparison tool, to check for differences. Both tools told me that the content is identical. I'm losing my mind, why does PowerShell tell me they have complete different content?
Sadly, I cannot post the content of the API response as well as the content of the index.html
What I thought maybe could be the reason is
Encoding, however both are UTF8
Line endings, however no diff if I use CL, CL RF or RF on the file
Some hidden characters (tabs instead of spaces) but I activated to see that on JetBrains IDE and they still are identical.
How do I know what's causing this issue here?
Not sure if Compare-Object is the right choice here. As the name says, it's for objects. Why not use the equals-operator -eq or string.Equals?
$equal = $testContent -eq $result
# or
$equal = $testContent.Equals($result)
Compare-Object does not do line-by-line-comparison if both are just single strings. So your strings are not equal, as long as there's any tiny difference, as much as just an extra line-feed at the end, etc.
You could try several things:
# trim
$equal = $testContent.Trim() -eq $result.Trim()
# case-insensitive comparison
$equal = $testContent.Equals($result, 'OrdinalIgnoreCase')
# or both
$equal = $testContent.Trim().Equals($result.Trim(), 'OrdinalIgnoreCase')
Btw: If you do want a line-by-line-comparison, you have to split up the strings into lines first, e.g.:
Compare-Object ($testContent -split "`r`n") ($result -split "`r`n")

How to use a post request correctly within powershell

Currently I am trying to work with an API that is utilizing cURL and I am trying to convert it to PowerShell.
Currently the example given by this company is by using cURL is:
$ curl -X POST -u "youruser:yourkey" -H "Content-Type: application/json"
"https://falconapi.crowdstrike.com/detects/entities/summaries/GET/v1" -d
'{"ids": ["ldt:ddaab9931f4a4b90450585d1e748b324:148124137618026"]}'
Right now I am trying to convert this within powershell by using the Invoke-WebRequest method using the following:
Invoke-WebRequest -Method Post -Uri $site -Body -Credential 'whatever credentials' |
ConvertFrom-Json | Select -ExcludeProperty resources
The part I am getting confused on is how to format the -Body request to be something similar to:
'{"ids": ["ldt:ddaab9931f4a4b90450585d1e748b324:148124137618026"]}'
where the LDT part is I am going through an array so instead of the ldt I am trying to call a variable such as $detections, but I am unable to.
You could just create a hash table and convert to json:
-body (#{ids = ($detections)} | ConvertTo-Json)
or if detections is an array you could omit the () around $detections
You aren't able to use a variable because you're using single quoted ' strings, which don't interpret variables or escape sequences. You need to use a double quoted " string for that. Since your string contains double quotes you'd need to escape them with PowerShell's escape character, which is the backtick `.
"{`"ids`": [`"ldt:$detections`"]}"
This likely not what you want though; you probably want to serialize the array into JSON, in which case you should use 4c74356b41's answer; that is: create an object with the values you want and then convert it to JSON at runtime. This is much less error prone.
You could use double quoted strings around the outside of your JSON body and then you are able to include the variable:
Invoke-WebRequest -Method Post -Uri "{'ids': ['ldt:$detections']}" -Body -Credential 'whatever credentials' |
ConvertFrom-Json | Select -ExcludeProperty resources

Select-String -Pattern Output when piping into

I try to get PowerShell to spit out a Semantic Versioning Variable but get stuck in it displaying just the command I entered (doing that in the ISE) or either of 2 errors ('missing argument' or 'doesn't accept piped input'), which, if I try to resolve them, end in the command simply being displayed again.
How do I get this:
(Invoke-WebRequest -Uri http://someplace).Links.href | Out-String -Stream |
Select-String -Pattern [regex]$someGoodRegex -OutVariable $NodeVersion_target
assuming the regex and web request point to solid things to simply stick the searched term in the -OutVariable defined?
On a more general note, is there a good way to display the properties of the objects in the pipe? After a great deal of digging, I stumbled upon {$_} but can't get it to display anything but the command again if the command gets a little more complex that just a simple cmdlet.
Remove the [regex]. Select-String already treats the argument to the parameter -Pattern as a regular expression.
Remove the $ from the variable name. You need it to use a variable directly, but the -OutVariable parameter expects the bare variable name without the leading $.
You can also remove the Out-String -Stream.
Something like this should work:
$uri = 'http://www.example.com/'
$re = 'v\d+\.\d+\.\d+/s'
(Invoke-WebRequest -Uri $uri).Links.href |
Select-String -Pattern $re -OutVariable NodeVersion_target
Alternatively you can assign the output of the pipeline to a variable instead of using -OutVariable:
$uri = 'http://www.example.com/'
$re = 'v\d+\.\d+\.\d+/s'
$NodeVersion_target = (Invoke-WebRequest -Uri $uri).Links.href |
Select-String -Pattern $re
The latter is actually more PoSh.
As for inspecting the current object in a pipeline: pipe into Get-Member to get a list of the properties/methods of the pipelined objects, and pipe into Format-List * to get a list of the values of the pipelined objects.

PowerShell Get links from FTP Site

I'm trying to create a list of all the links from an FTP site. The links are to download zip files.
My end goal is to analyze each link as a string and match the beginning to a set phrase. The end of each link contains a date and I have to find the newest one to download.
In this example I want to find ABC_20170323.zip out of this list:
ABC_20170323.zip
ABC_20160102.zip
EFG_20170324.zip
I need to figure out how to acquire the links before analysis. I've tried a variety of methods and the only one that has returned any information from the site is to gather the source code:
Invoke-WebRequest $sourceuri -UseBasicParsing -Credential $user
But then I find it difficult to gather all the links from there. Anyone have a method for easily getting these file download links?
Okay, so I know it's been ages, but I figured out how to do it. Admittedly, it's the hard way. What ended up happening is I gathered the source code and saved it like so:
$r = Invoke-WebRequest $sourceuri -UseBasicParsing -credential $user
Then I converted it to a string and used -split to separate out the links by their html tag and what I expected the beginning to look like (in this case 'ABC'):
$c = $r.ToString() #convert to string
$datelist = #()
$f = ($c -split 'A HREF="' -split '.zip</A>') #split by html tag (and .zip)
foreach($link in $f){
if($link -match 'ABC') { #if the beginning of the link is 'ABC'
$datelist += ($link.substring($link.Length-8)) #isolate the date on the end
}
} #more logic for comparing $datelist items...
Then I wrote some logic for comparing the items in $datelist (Omitted from answer) and created a variable that had all the components I needed:
$ExactLink = "ABC_$GreatestDate" + ".zip"
Then went on to download the $ExactLink I needed.

Parsing HTML with PowerShell on dynamic sites

Is there a way to parse HTML from http://www.pgatour.com site using Invoke-WebRequest cmdlet? When I try doing this, ParsedHtml does not contain elements that I need (because cmdlet incorrectly parses the page).
I tried getting data from this page by creating IE COM object in PowerShell and it works, but very slow, so I'm wondering if there is another approach using Invoke-WebRequest (or even external parsers).
Thanks!
You could give the HmtlAgilityPack a try to parse the content returned by Invoke-WebRequest. In this scenario, I would use the -UseBasicParsing parameter.
Window 10 64-bit. PowerShell 5.1
Parsing HTML with PowerShell 5.1 on dynamic sites using Invoke-WebRequest and a regex that returns everything between un-nested tags like <html>,<title>,<head>, and <body>. It will take some tweaking for nested tags.
Invoke-WebRequest -Uri http://www.pgatour.com | sc golf.html
(gc -raw golf.html) -match '(<body>)(.*|\n).*?(<\/body>)'
$matches[0]
Everything between <div class="success-message"> and the next </div>
Invoke-WebRequest -Uri http://www.pgatour.com | sc golf.html
(gc -raw golf.html) -match '(<div class="success-message">)(.*?|\n)*(<\/div>)'
$matches[0]
Greedy and lazy quantifiers explained
regex101.com is your friend.