Foreach and If linked issue - powershell

Here after my code for which I have an issue:
#Delivery Groups Information
$dgroup = Invoke-RestMethod -Uri "https://${XMS}:4443/xenmobile/api/v1/deliverygroups/filter" -Body '{}' -Headers $headers -Method Post
$new = 0
$count = $dgroup.dglistdata.dglist.length
for ($v=0; $v -lt $count; $v++) {
foreach ($dglistdata in $dgroup) {
Write-Host $dglistdata.dglistdata.dglist[$new].name
$new++
}
}
$Host.UI.RawUI.ForegroundColor = "white"
$dgroup = Read-Host -Prompt "Please provide Delivery Group Name for which notification will be sent"
$message = Read-Host -Prompt "Please provide the message to be sent"
#Devices
$devices = Invoke-RestMethod -Uri "https://${XMS}:4443/xenmobile/api/v1/device/filter" -Body '{}' -Headers $headers -Method Post
foreach ($device in $devices.filteredDevicesDataList) {
Write-Output $device.id >$null
Write-Output $device.platform >$null
}
foreach ($device in $devices.filteredDevicesDataList) {
$url = "https://${XMS}:4443/xenmobile/api/v1/device/" + $device.id + "/deliverygroups"
$global:dg = Invoke-RestMethod -Uri $url -Headers $headers -Method Get
foreach($deliverygroups in $dg) {
Write-Output $dg.deliveryGroups.name >$null
}
}
foreach ($device in $devices.filteredDevicesDataList) {
if ($dg.deliveryGroups.name -match $dgroup) {
Write-Host $device.devicemodel
Send-Notification
} else {
$dgroup = 0
}
}
Info:
The main object of the code is to send notification to devices based on which group devices are member of.
Example:
iPad member of "DG 2"
iPhone member of "DG 1"
Result:
Do I miss something there?

In fact, I think I found the solution, I need to include my loop for notification in the other loop as:
foreach($device in $devices.filteredDevicesDataList)
{
$url = "https://${XMS}:4443/xenmobile/api/v1/device/" + $device.id + "/deliverygroups"
$Global:dg=Invoke-RestMethod -Uri $url -Headers $headers -Method Get
foreach($deliverygroups in $dg)
{
write-output $dg.deliveryGroups.name >$Null
If($dg.deliveryGroups.name -match $dgroup)
{
write-host $device.devicemodel
Send-notification
}
}
}

Related

Can I export azure devops pipelines run history using Powershell?

So what I want to know is if its possible to generate a report that will tell us all the pipelines that have been run in the past month, how long they took, any failures.
If so, how can I do it?
Here is some script iv got so far
$strURL = "https://dev.azure.com/{chealey}/{personal test}/_apis/build/builds?api-version=5.1"
$filePath="D:\"
$fileName=$filePath+"\pipeline.json"
$pipeline = Invoke-RestMethod -Uri $strURL -Headers #{
Authorization = "Bearer $env:SYSTEM_ACCESSTOKEN"
} -Method GET -OutFile $fileName
You can RUNS Rest Api: https://learn.microsoft.com/en-us/rest/api/azure/devops/pipelines/runs/list?view=azure-devops-rest-6.1
As example:
$user = ""
$token = $env:SYSTEM_ACCESSTOKEN
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$orgUrl = $env:SYSTEM_COLLECTIONURI
$teamProject = $env:SYSTEM_TEAMPROJECT
$restApiGetBuildDefinitions = "$orgUrl/$teamProject/_apis/build/definitions?api-version=6.1-preview.7"
$restApiGetBuildRunsTemplate = "$orgUrl/$teamProject/_apis/pipelines/{BUILD_DEF_ID}/runs?api-version=6.1-preview.1"
function InvokeGetRequest ($GetUrl)
{
return Invoke-RestMethod -Uri $GetUrl -Method Get -ContentType "application/json" -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}
}
$buildDefs = InvokeGetRequest $restApiGetBuildDefinitions
foreach ($buildDef in $buildDefs.value)
{
$restApiGetBuildRuns = $restApiGetBuildRunsTemplate -replace "{BUILD_DEF_ID}", $buildDef.id
$buildRuns = InvokeGetRequest $restApiGetBuildRuns
if ($buildRuns.count -gt 0)
{
Write-Host "Build Definition:" $buildDef.name
Write-Host "| Run Id | Start Date | Finish Date | Result |"
Write-Host "|--------|------------|-------------|--------|"
foreach ($buildRun in $buildRuns.value)
{
Write-Host "|" $buildRun.id "|" $buildRun.createdDate "|" $buildRun.finishedDate "|" $buildRun.result "|"
}
}
}

Nessus IO Powershell API HTML/PDF report

When exporting PDF & HTML format reports the reports are empty, best I can tell there needs to be a report attribute but after 5 hours of running through the API and searching every which way I can think of I am not finding anything referencing that.
For those interested, this is the starting script before I started optimizing it.
https://github.com/Pwd9000-ML/NessusV7-Report-Export-PowerShell/blob/master/NessusPro_v7_Report_Exporter_Tool.ps1
add-type #"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}
}
"#
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
[System.Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$GNR = #{
OutputDir = "$Env:SystemDrive\Nessus\$(([DateTime]::Now).ToString("yyyy-MM-dd"))"
StatusUri = [System.Collections.ArrayList]::new()
}
#------------------Input Variables-----------------------------------------------------------------
$Baseurl = "https://$($env:COMPUTERNAME):8834"
$Username = <Removed>
$Password = <Removed>
$ContentType = "application/json"
$POSTMethod = 'POST'
$GETMethod = 'GET'
#------------------Stage props to obtain session token (Parameters)--------------------------------
$session = #{
Uri = $Baseurl + "/session"
ContentType = $ContentType
Method = $POSTMethod
Body = convertto-json (New-Object PSObject -Property #{username = $Username; password = $Password})
}
#------------------Commit session props for token header X-cookie----------------------------------
$TokenResponse = Invoke-RestMethod #session
if ($TokenResponse) {
$Header = #{"X-Cookie" = "token=" + $TokenResponse.token}
} else {
Write-nLog -Message "Error occured obtaining session token. Script Terminating... Please ensure Username and Password Correct." -Type Error -TerminatingError
}
IF (![System.IO.Directory]::Exists($GNR.OutputDir)) {
New-Item -Path $GNR.OutputDir -ItemType directory -Force |Out-Null
}
#------------------Output completed scans----------------------------------------------------------
$Scans = (Invoke-RestMethod -Uri "$baseurl/scans" -Headers $Header -Method $GETMethod -ContentType "application/json").scans
ForEach ($Format in #("nessus","pdf")) {
$StatusURI = [System.Collections.ArrayList]::new()
$StatusArray = [System.Collections.ArrayList]::new()
ForEach ($Scan in $Scans) {
Add-Content -Path "$($GNR.OutputDir)\ScanReport.txt" -Value "$($Scan.Name) ($($Scan.status))"
IF ($Scan.status -eq "Completed") {
$File = (Invoke-RestMethod -URI "$baseurl/scans/$($Scan.ID)/export" -ContentType $ContentType -Headers $Header -Method $POSTMethod -Body $(convertto-json (New-Object PSObject -Property #{format = "$Format"}))).file
[Void]$StatusArray.Add(
[pscustomobject]#{
ScanName = $scan.name
StatusUri = $baseurl + "/scans" + "/" + $Scan.id + "/export/" + "$file" + "/status"
DownloadUri = $baseurl + "/scans" + "/" + $Scan.id + "/export/" + "$file" + "/download"
}
)
}
}
#------------------Check Status of Export requests-------------------------------------------------
While ($StatusArray.StatusUri.count -GT $StatusURI.Count) {
ForEach ($ScanStatus in $StatusArray.StatusURI) {
IF ((Invoke-RestMethod -Uri $ScanStatus -ContentType $ContentType -Headers $Header -Method $GETMethod).status -EQ "Ready") {
if ($StatusURI -notcontains $ScanStatus) {
Write-Host "Adding $ScanStatus"
[void]$StatusURI.Add($ScanStatus)
}
} Else {
Write-nLog -Type "Info" -Message "Not all scans complete. ($($GNR.StatusURI.Count)/$($StatusArray.StatusUri.count)"
Start-Sleep -s 5
}
}
}
#------------------Download the Reports------------------------------------------------------------
$ExportUri = $StatusArray.DownloadUri
$outputs = $StatusArray.ScanName
foreach ($i in 0..($ExportUri.Count - 1)) {
Write-nLog -Type Info -Message "Exporting Report: $($outputs[$i])"
Invoke-WebRequest -Uri $ExportUri[$i] -ContentType $ContentType -Headers $Header -Method $GETMethod -OutFile "$($GNR.OutputDir)\$($outputs[$i]).$Format"
}
}
#------------------Script END----------------------------------------------------------------------
There are several additional parameters you can set on the POST /scans/{id}/export endpoint. The important one missed here is chapters which accepts a semi-colon delimted list of the desired content sections. This must be set for exports of pdf or html types, otherwise you get an empty result.
For example, to get the executive summary, in addition to format of html/pdf/csv etc, set chapters to vuln_hosts_summary. The other available options are:
vuln_by_host
compliance_exec
remediations
vuln_by_plugin
compliance
Hopefully this helps the next person trying to debug empty Nessus API exports too!
For full API docs for your version check out https://{YOUR_NESSUS_INSTALL}/api

Pass entire hashtable to Invoke-Expression

I would like to ask you for an question about passing hashtable to Invoke-Expression.
Iam writing simple E2E monitoring and mentioned hashtable is used as a body containing creds for HTTP form to log jira.
It works for me fine, but from specific reason I would like to create this Invoke-Webrequest dynamically, depending on recieved arguments.
And there is my catch.
Thus, I don't know, how to pass hashtable (other data types are ok, like a string or int) to Invoke Expression.
It is always presented like System.Collections.Hashtable
$uri = 'https://exdom.com/login.jsp?saml_sso=false'
$method = "POST"
$postParams = #{
os_username = "username";
os_password = "password";
login = "true"
}
$scriptBlock = {
param(
[Parameter(Mandatory=$true,Position=1)][string]$uri,
[Parameter(Mandatory=$false,Position=2)][string]$method,
[Parameter(Mandatory=$true,Position=3)][hashtable]$postParams
)
$commandFragments = #()
$commandFragments += "Invoke-WebRequest"
if ( $PSBoundParameters.ContainsKey('uri')){
$commandFragments += " -Uri $uri"
}
if ( $PSBoundParameters.ContainsKey('method')){
$commandFragments += " -Method $method"
}
if ( $PSBoundParameters.ContainsKey('postParams')){
$commandFragments += " -Body $postParams"
}
$commandFromFragments = $commandFragments -join ''
(Invoke-Expression -Command $commandFromFragments).Content | Out-File 'c:\tmp\response3.html'
(Invoke-Expression -Command "Invoke-WebRequest -Uri https://exdom.com/login.jsp?saml_sso=false -Method POST -Body #(#{'os_username' = 'username#mydomain.com'; 'os_password' = 'mypassword'; 'login' = 'true'})").Content | Out-File 'c:\tmp\response4.html'
(Invoke-WebRequest -Method $method -Uri $uri -Body $postParams).Content | Out-File 'c:\tmp\response5.html'
}
Invoke-Command -ScriptBlock $scriptBlock -ArgumentList ($uri, $method, $postParams)
Iam missing something basic, I guess.
May I ask you for an advice?
Thanks, Marcel
Lets talk about whats wrong.
$commandFragments += " -Body $postParams"
You are turning a HashTable into a string. Which is not possible. So what we can do is convert it into something. Now what should we convert into? Invoke-WebRequest -body
This can be done with Json. So you could use " -Body $($postParams | convertto-json)"
But this is only saving the json to a string which still wouldnt work because the Json needs to be in a string inside the command Invoke-WebRequest. So the fix would be to surround the JSON with single quotes. " -Body '$($postParams | ConvertTo-Json)'"
We also have some small fixes we can do for efficiency. Like the if statements looking
$PSBoundParameters.GetEnumerator() | %{
switch($_.Key){
"uri" { $commandFragments += " -Uri $uri" }
"method" { $commandFragments += " -Method $method" }
"postParams" { $commandFragments += " -Body '$($postParams | ConvertTo-Json)'" }
}
}
The final product being
$uri = 'https://exdom.com/login.jsp?saml_sso=false'
$method = "POST"
$postParams = #{
"os_username" = "username";
"os_password" = "password";
"login" = "true"
}
$scriptBlock = {
param(
[Parameter(Mandatory=$true,Position=1)][string]$uri,
[Parameter(Mandatory=$false,Position=2)][string]$method,
[Parameter(Mandatory=$true,Position=3)][hashtable]$postParams
)
$commandFragments = $("Invoke-WebRequest")
$PSBoundParameters.GetEnumerator() | %{
switch($_.Key){
"uri" { $commandFragments += " -Uri $uri" }
"method" { $commandFragments += " -Method $method" }
"postParams" { $commandFragments += " -Body '$($postParams | ConvertTo-Json)'" }
}
}
(Invoke-Expression -Command $($commandFragments -join '')).Content | Out-File 'c:\tmp\response3.html'
(Invoke-Expression -Command "Invoke-WebRequest -Uri https://exdom.com/login.jsp?saml_sso=false -Method POST -Body #(#{'os_username' = 'username#mydomain.com'; 'os_password' = 'mypassword'; 'login' = 'true'})").Content | Out-File 'c:\tmp\response4.html'
(Invoke-WebRequest -Method $method -Uri $uri -Body $postParams|ConvertTo-Json).Content
}
Invoke-Command -ScriptBlock $scriptBlock -ArgumentList ($uri, $method, $postParams)

PowerShell. Catch error. How add body to Invoke-RestMethod?

I need to add this model:
{ "sourceVersion": "5ddcada97436a83dfedf5b41261ef9bfb8b718d7", "debug": true }
but PowerShell Console shows me Error "Bad Request."
This is my Code:
try {
$serverHost = "api.appcenter.ms"
$service = "https://$serverHost/v0.1/apps/App/App/branches/dev/builds"
$ContentType = "application/json" # Add the content type
$Method = 'POST' # Add the method type
$Body = '{ "sourceVersion" = "5ddcada97436a83dfedf5b41261ef9bfb8b718d7", "debug" = True }'
$Headers = #{'accept'='application/json';'X-API- Token'='efa699e279155919d4ed7ca880e335ebd7ad8191'}
$result = Invoke-RestMethod -Method POST -Uri $service -Headers $Headers - Body $Body
Read-Host -Prompt $result
}
catch {
Write-Error $_.Exception.ToString()
Read-Host -Prompt "The above error occurred. Press Enter to exit."
}

How to pass optional parameters in PowerShell?

This is a wrapper function for Invoke-WebRequest (I have removed a lot of extra functionality to keep the noise down)
function Invoke-SERVERAPI($apiFolder, $adminCredentials, [ValidateSet("GET","POST","PUT","DELETE")] $HTTPmethod, $contentType, $body, $verbose)
{
$resp1HTTPCode= 'Not set'
try
{
if ( ($HTTPmethod -eq 'GET') -or ($HTTPmethod -eq 'DELETE'))
{
$resp1 = Invoke-WebRequest -Uri $apiFolder -Method $HTTPmethod -Credential $adminCredentials -ContentType $contentType -ErrorAction SilentlyContinue -Verbose:$verbose
}
else
{
$resp1 = Invoke-WebRequest -Uri $apiFolder -Body $body -Method $HTTPmethod -Credential $adminCredentials -ContentType $contentType -ErrorAction SilentlyContinue -Verbose:$verbose
}
$resp1HTTPCode = $resp1.StatusCode
}
catch [Exception]
{
$resp1HTTPCode = $_.Exception.Response.StatusCode.Value__
}
return $resp1HTTPCode
}
I need to pass -body parameter on verb POST and PUT but don't pass it in GET and DELETE. I managed to do it with an IF/ELSE.
Is there a better way to achieve this in PowerShell like I did in the switch parameter -Verbose?
Yes, it involves forming a hashtable with parameters and using that instead or in addition of parameter list, aka splatting. In your case, you do like this:
try
{
$ifbody=#{}
if ( ($HTTPmethod -eq 'PUT') -or ($HTTPmethod -eq 'POST'))
{
$ifbody."Body"=$body
}
$resp1 = Invoke-WebRequest -Uri $apiFolder #ifbody -Method $HTTPmethod -Credential $adminCredentials -ContentType $contentType -ErrorAction SilentlyContinue -Verbose:$verbose
$resp1HTTPCode = $resp1.StatusCode
}
The #ifbody reverts the hashtable into -key=value -key2=value2... sequence of parameters to a cmdlet or a function.
You should have a look at ParameterSetName in about_Functions_Advanced_Parameters. It can help you to differentiate different sets of parameters.