Powershell Google GeoLocation script - google-maps

Api key here
function Get-ComputerGeoLocation ()
{
echo debug 1
# Windows Location API
$mylocation = new-object –ComObject LocationDisp.LatLongReportFactory
# Get Status
$mylocationstatus = $mylocation.status
If ($mylocationstatus -eq "4")
{
# Windows Location Status returns 4, so we're "Running"
echo debug 2
# Get Latitude and Longitude from LatlongReport property
$latitude = $mylocation.LatLongReport.Latitude
$longitude = $mylocation.LatLongReport.Longitude
if ($latitude -ne $null -or $longitude -ne $Null)
{
echo debug 3
# Retrieve Geolocation from Google Geocoding API
$webClient = New-Object System.Net.WebClient
Write-host "Retrieving geolocation for" $($latitude) $($longitude)
$url = "https://maps.googleapis.com/maps/api/geocode/xml?latlng=$latitude,$longitude'&'amp;sensor=true"
$locationinfo = $webClient.DownloadString($url)
echo debug 4
[xml][/xml]$doc = $locationinfo
# Verify the response
if ($doc.GeocodeResponse.status -eq "OK")
{
$street_address = $doc.GeocodeResponse.result | Select-Object -Property formatted_address, Type | Where-Object -Property Type -eq "street_address"
$geoobject = New-Object -TypeName PSObject
$geoobject | Add-Member -MemberType NoteProperty -Name Address -Value $street_address.formatted_address
$geoobject | Add-Member -MemberType NoteProperty -Name latitude -Value $mylocation.LatLongReport.Latitude
$geoobject | Add-Member -MemberType NoteProperty -Name longitude -Value $mylocation.LatLongReport.longitude
$geoobject | format-list
}
Else
{
Write-Warning "Request failed, unable to retrieve Geo locatiion information from Geocoding API"
}
}
Else
{
write-warning "Latitude or Longitude data missing"
}
}
Else
{
switch($mylocationstatus)
{
# All possible status property values as defined here:
# http://msdn.microsoft.com/en-us/library/windows/desktop/dd317716(v=vs.85).aspx
0 {$mylocationstatuserr = "Report not supported"}
1 {$mylocationstatuserr = "Error"}
2 {$mylocationstatuserr = "Access denied"}
3 {$mylocationstatuserr = "Initializing" }
4 {$mylocationstatuserr = "Running"}
}
If ($mylocationstatus -eq "3")
{
write-host "Windows Loction platform is $mylocationstatuserr"
sleep 5
Get-ComputerGeoLocation
}
Else
{
write-warning "Windows Loction platform: Status:$mylocationstatuserr"
}
}
} # end function
Get-ComputerGeoLocation
So I am typing in the terminal "get-computergeolocation"
The error is:
At C:\Users\xxxxx\Documents\files\powershell\computerLocation.ps1:72 char:77
+ ... write-warning "Windows Loction platform: Status:$mylocationstatuserr"
+ ~
The string is missing the terminator: ".
At C:\Users\xxxxx\Documents\files\powershell\computerLocation.ps1:4 char:1
+ {
+ ~
Missing closing '}' in statement block or type definition.
+ CategoryInfo : ParserError: (:) [], ParseException
+ FullyQualifiedErrorId : TerminatorExpectedAtEndOfString
I am not sure, it is giving back a syntax error, but I don't think it is a syntax error.
I sifted through the code to see if there was a syntax error and came up with nothing, at least with what the terminal was spitting out.
The code should find my latitude and longitude and give me an address (end result). This is going to be tied together in another program that determines the users home address based on IP.
====================================
UPDATED
I updated the script. I took out everything that wasn't important to keep it super simple to try to narrow down the error.
function Get-123(){
$env:GoogleGeoloc_API_Key = "key"
echo debug 1
# Windows Location API
$mylocation = new-object –ComObject LocationDisp.LatLongReportFactory
# Get Status
$mylocationstatus = $mylocation.status
If ($mylocationstatus -eq "4"){
# Windows Location Status returns 4, so we're
echo debug 2
# Get Latitude and Longitude from LatlongReport property
$latitude = $mylocation.LatLongReport.Latitude
$longitude = $mylocation.LatLongReport.Longitude
if ($latitude -ne $null -or $longitude -ne $Null){
echo debug 3
# Retrieve Geolocation from Google Geocoding API
$webClient = New-Object System.Net.WebClient
Write-host "Retrieving geolocation for" $($latitude) $($longitude)
#$u = "https://maps.googleapis.com/maps/api/geocode/xml?latlng=$latitude,$longitude"
#$r = '&'
#$l = "amp;sensor=true"
$url = “https://maps.googleapis.com/maps/api/geocode/xml?latlng=$latitude,$longitude&sensor=true”
$locationinfo = $webClient.DownloadString($url)
echo debug 4
[xml]$doc = $locationinfo
# Verify the response
if ($doc.GeocodeResponse.status -eq "OK"){
$street_address = $doc.GeocodeResponse.result | Select-Object -Property formatted_address, Type | Where-Object {$_.Property -eq "street_address"}
$geoobject = New-Object -TypeName PSObject
$geoobject | Add-Member -MemberType NoteProperty -Name Address -Value $street_address.formatted_address
$geoobject | Add-Member -MemberType NoteProperty -Name latitude -Value $mylocation.LatLongReport.Latitude
$geoobject | Add-Member -MemberType NoteProperty -Name longitude -Value $mylocation.LatLongReport.longitude
$geoobject | format-list
}
}
}
} # end function
#Get-ComputerGeoLocation
get-123
I Can't find this syntax error.... I am not even sure it is a syntax error....
At C:\Users\p617824\Documents\files\powershell\computerLocation.ps1:36 char:148
+ ... atted_address, Type | Where-Object {$_.Property -eq "street_address"}
+ ~~
The string is missing the terminator: ".
At C:\Users\p617824\Documents\files\powershell\computerLocation.ps1:4 char:1
+ {
+ ~
Missing closing '}' in statement block or type definition.
+ CategoryInfo : ParserError: (:) [], ParseException
+ FullyQualifiedErrorId : TerminatorExpectedAtEndOfString

Related

How to create JSON payload using power shell Foreach loop

Requirement: To send E-Mail via send grid account (Send Grid API) by attaching multiple attachments.
Description: I am able to create json payload and able to send with single attachment by hard coding attachment values. I am opening window forms dialog and able to select single/multiple files that needs to be attached.
Code:
$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property #{
InitialDirectory = [Environment]::GetFolderPath('Desktop')
#Filter = 'Documents (*.docx)|*.docx|SpreadSheet (*.xlsx)|*.xlsx'
Filter = 'All files (*.*)| *.*'
Title = 'Select File(s) for Attachments'
Multiselect = $true
}
$FileBrowser.ShowDialog() | Out-Null
$FilesEncodedContents = New-Object System.Collections.ArrayList
$AttachmentsjsonRequest = #()
if ($FileBrowser.FileNames.Count -gt 0) {
foreach ($file in $FileBrowser.FileNames) {
[string] $filerawContent = $null
$filedetails = Get-Item $file
$filerawContent = ConvertToBase64Encode $file
if (![string]::IsNullOrWhitespace($filerawContent)) {
$FilesEncodedContents.Add($filerawContent)
$obj = New-Object -TypeName PSObject
$obj | Add-Member -MemberType NoteProperty -Name filename -Value (Get-Item $file).Name
$obj | Add-Member -MemberType NoteProperty -Name content_id -Value (Get-Item $file).Name
$obj | Add-Member -MemberType NoteProperty -Name content -Value $filerawContent
$obj | Add-Member -MemberType NoteProperty -Name disposition -Value 'attachment'
$AttachmentsjsonRequest += $obj
}
}
}
Write-Host "$AttachmentsjsonRequest"
$headers = #{ }
$headers.Add("Authorization", "Bearer $ApiKey")
$headers.Add("Content-Type", "application/json")
$jsonRequest = [ordered]#{
personalizations = #(#{to = #(#{email = "$MailTo" })
subject = "$Subject"
})
from = #{email = "no-reply#xxx.com" }
attachments = "$AttachmentsjsonRequest"
content = #( #{ type = "text/plain"
value = "Sample Mail Body"
}
)
} | ConvertTo-Json -Depth 100
Write-Host $jsonRequest | ConvertTo-Json -Depth 100
Invoke-RestMethod -Uri "https://api.sendgrid.com/v3/mail/send" -Method Post -Headers
$headers -Body $jsonRequest
Write-Host "Mail Sent"
#region ConvertToBase64Encode
Function ConvertToBase64Encode([string] $AttachementFile) {
[string] $fileContentEncoded = $null
if (Test-Path $AttachementFile -PathType leaf) {
$fileContent = get-content $AttachementFile
$fileContentBytes = [System.Text.Encoding]::UTF8.GetBytes($fileContent)
$fileContentEncoded = [System.Convert]::ToBase64String($fileContentBytes)
$fileContentEncoded | set-content ((Get-Item -Path $AttachementFile).Name + ".b64")
}
else {
$fileContentEncoded = $null
Write-Host "File : $FileAttachment not exists,skipping and continue to add if any other
attachments uploaded"
}
return $fileContentEncoded
}
#endregion
Problem: [UPDATED]
Am getting below error after trying to upload single or multiple attachments
{"errors":[{"message":"Invalid type. Expected: array, given: string.","field":"attachments","help":"http://sendgrid.com/docs/API_Reference/Web_API_v3/Mail/errors.html#message.attachments"}]} .
Reference Links :
Send Grid API Documentation:
https://sendgrid.com/docs/API_Reference/api_v3.html
My advice is to consider not building the JSON as a text, first build a Powshell object that you convert to JSON with ConvertTo-Json.
Using this method, arrays will be correctly represented in JSON. don't forget to set the -DEPTH param.
attachments array[object] An array of objects in which you can specify any attachments you want to include.
So in your Powershell object attachments is going to be a #().
of objects with content, type, filename, disposition, conten_id properties.
I realized error details in depth in late . It was giving hint in JSON payload "attachments" field is showing as string rather than array object which it is fixed by adding #(#()) to attachmentjsonrequest in "$jsonrequest" variable .
In Short: "attachmentjsonrequest is an array object which needs to convert to JSON payload by using #()
Thanks for suggesting to use array object.
attachments = #(#($AttachmentsjsonRequest))

ConvertTo-HTML outputs System.Object[] from PSObject

I try to convert a PSObject to a HTML table and get System.Object[] as output.
$Result = New-Object PSObject
foreach ($Location in $Locations) {
$Servers = GetServers -Location $Location
$Value = #()
foreach ($Server in $Servers) {
if (Test-Path Path) {
$value += $Server #Background of td should be green
} else {
$Value += $Server #Background of td should be red
}
}
$Result | Add-Member -Type NoteProperty -Name $Location -Value $Value
}
$Result ConvertTo-Html
Without converting to HTML the output is:
Location1 : {Server1, Server2}
Location2 : {Server3, Server4}
Location3 : {Server5, Server6}
Trying to convert:
<td>System.Object[]</td>
And I'd like to have a table like:
Location1 Location2 Location3
--------- --------- ---------
Server1 Server3 Server5
Server2 Server4 Server6
If it's possible I would like to have different <td> background (as commented in the script).
ConvertTo-Html doesn't know how to format string arrays, so you'll have to convert the value to a string before passing it to the cmdlet:
$Result | Add-Member -Type NoteProperty -Name $Location -Value ($Value -join ', ')

Powershell: Get-Content from the large file (server list) [duplicate]

This question already has answers here:
Can Powershell Run Commands in Parallel?
(10 answers)
Closed 6 years ago.
I have 100,000 list of servers from the text file (serverlist.txt)
When I run in one shot it will burst my memory and cpu and the time took longer (about 3 days)to complete the scanning for DNSlookup.
I tried to split the file that contain 20k list of servers below and can be completed to scan up to 10mins for each file.
serverlist1.txt
serverlist2.txt
serverlist3.txt
serverlist4.txt
serverlist5.txt
$objContainer = #()
$values = #()
$domains = Get-Content -path "serverlist1.txt"
$named = 0
$timestamp= get-date
$domains | ForEach-Object {
$domain = $_
nslookup $domain 2>&1 | ForEach-Object {
if ($_ -match '^Name:\s*(.*)$') {
$values += $matches[1]
$named = 1;
} elseif (($_ -match '^.*?(\d*\.\d*\.\d*\.\d*)$') -and ($named -eq 1)) {
$values += $matches[1]
} elseif ($_ -match '^Aliases:\s*(.*)$') {
$values += $matches[1]
}
}
$obj = New-Object -TypeName PSObject
#$obj | Add-Member -MemberType NoteProperty -name 'Domain' -value $domain
$obj | Add-Member -MemberType NoteProperty -name 'Name' -value $values[0]
$obj | Add-Member -MemberType NoteProperty -name 'IP Address' -value $values[1]
$obj | Add-Member -MemberType NoteProperty -name 'Alias' -value $values[2]
$obj | Add-Member -MemberType NoteProperty -name 'Timestamp' -value $timestamp
$objContainer += $obj
$values = #()
$named = 0
}
Write-Output $objContainer
$objContainer | Export-csv "dnslog_$((Get-Date).ToString('MM-dd-yyyy_hh-mm-ss')).csv" -NoTypeInformation
My question is, how to execute at once and looping the input from the text file after generate the dnslog(datetime).csv
e.g:
run the powershell script .\filename.ps1
input from serverlist1.txt
output dnslog(datetime).csv
input from serverlist2.txt
output dnslog(datetime).csv
input from serverlist3.txt
output dnslog(datetime).csv
input from serverlist4.txt
output dnslog(datetime).csv
input from serverlist5.txt
output dnslog(datetime).csv
Finish!
If i have more then 5 list of text file, it will continue to loop from the input file until completed.
Adding to Chris's answer I would also add a ReadCount flag to the Get-Content like so:
Get-Content -path "serverlist1.txt" -ReadCount 1 | % {
This will save having to read the entire file into memory.
You should consider running this a parallel batching job. Have you already tried doing so?
You can deal with the RAM busting problem by removing all those commits to memory (variable assignments and array rewriting with +=).
$timestamp = get-date
Get-Content -path "serverlist1.txt" | ForEach-Object {
$domain = $_
# You can clear this here.
$values = #()
$named = 0
# There are potentially better options than nslookup.
# Needs a bit of care to understand what's an alias here though.
# [System.Net.Dns]::GetHostEntry($domain)
# And if you don't like that, quite a few of us have written equivalent tools in PowerShell.
nslookup $domain 2>&1 | ForEach-Object {
if ($_ -match '^Name:\s*(.*)$') {
$values += $matches[1]
$named = 1;
} elseif (($_ -match '^.*?(\d*\.\d*\.\d*\.\d*)$') -and ($named -eq 1)) {
$values += $matches[1]
} elseif ($_ -match '^Aliases:\s*(.*)$') {
$values += $matches[1]
}
}
# Leave the output object in the output pipeline
# If you're running PowerShell 3 or better:
[PSCustomObject]#{
Domain = $domain
Name = $values[0]
'IP Address' = $values[1]
Alias = $values[2]
TimeStamp = $timestamp
}
# PowerShell 2 is less flexible. This or Select-Object.
#$obj = New-Object -TypeName PSObject
##$obj | Add-Member -MemberType NoteProperty -name 'Domain' -value $domain
#$obj | Add-Member -MemberType NoteProperty -name 'Name' -value $values[0]
#$obj | Add-Member -MemberType NoteProperty -name 'IP Address' -value $values[1]
#$obj | Add-Member -MemberType NoteProperty -name 'Alias' -value $values[2]
#$obj | Add-Member -MemberType NoteProperty -name 'Timestamp' -value $timestamp
# To leave this in the output pipeline, uncomment this
# $obj
# No version of PowerShell needs you to do this. It's a good way to ramp up memory usage
# for large data sets.
# $objContainer += $obj
} | Export-Csv "dnslog_$(Get-Date -Format 'MM-dd-yyyy_hh-mm-ss').csv" -NoTypeInformation

ConvertTo-Json on VMWare objects doesn't work

In powershell while converting VM objects to json ,
($json = ConvertTo-Json $vm -Compress)
i am getting "An item with the same key has already been added" exception.
PS SQLSERVER:\> C:\Users\admin\Desktop\inventory.ps1
ConvertTo-Json : An item with the same key has already been added.
At C:\Users\huradmin\Desktop\inventory.ps1:68 char:31
+ if($vm -ne $null){$json = ConvertTo-Json $vm -Compress; insertToElasticSearc ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [ConvertTo-Json], ArgumentException
+ FullyQualifiedErrorId : System.ArgumentException,Microsoft.PowerShell.Commands.ConvertToJsonCommand
insertToElasticSearch : Cannot bind argument to parameter 'json' because it is null.
At C:\Users\admin\Desktop\inventory.ps1:68 char:89
+ ... icSearch -json $json -info:$true -Verbose:$true}
+ ~~~~~
+ CategoryInfo : InvalidData: (:) [insertToElasticSearch], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,insertToElasticSearch
getVMHosts function returns a list of VM guests. Please find my code below.
function getVMHosts{
Param(
[Parameter(Mandatory=$True,Position=1)]
[string]$vcenter,
[Parameter(Mandatory=$False)]
[switch]$info=$false
)
try
{
Write-Verbose "$(get-date -Format "dd/MM/yyyy HH:mm") - Function:$($MyInvocation.MyCommand) - Importing VMWare modules" -verbose:$info
Get-Module -ListAvailable -Name "VMware.*" | Import-Module
Write-Verbose "$(get-date -Format "dd/MM/yyyy HH:mm") - Function:$($MyInvocation.MyCommand) - Connecting to Vcenter:$vcenter" -verbose:$info
[void]::$(Connect-VIServer -Server $vcenter -ErrorAction SilentlyContinue)
Write-Verbose "$(get-date -Format "dd/MM/yyyy HH:mm") - Function:$($MyInvocation.MyCommand) - Getting Data center servers" -verbose:$info
$DCs = Get-Datacenter
$VMs = $null
foreach($dc in $DCs)
{
Write-Verbose "$(get-date -Format "dd/MM/yyyy HH:mm") - Function:$($MyInvocation.MyCommand) - Getting VM servers for Data Center:$dc" -verbose:$info
$VMs=$VMs+ $(Get-Datacenter -Name $dc.Name | Get-VM -Verbose:$info| Select PowerState,Name, NumCpu,MemoryMB,GuestId,VMHost, #{N="IP Address";E={#($_.guest.IPAddress[0])}})
}
Write-Verbose "$(get-date -Format "dd/MM/yyyy HH:mm") - Function:$($MyInvocation.MyCommand) - Disconnecting from VCenter:$vcenter" -verbose:$info
Disconnect-VIServer -Server $vcenter -ErrorAction SilentlyContinue -Confirm:$false
Write-Verbose "$(get-date -Format "dd/MM/yyyy HH:mm") - Function:$($MyInvocation.MyCommand) - Returning VM Lists" -verbose:$info
return $VMs
}
catch
{
$errorMessage = "$($_.Exception.Message)`n$(($_|select -ExpandProperty invocationinfo).PositionMessage)"
Write-Warning -Message "Catched an exception in Function:$($MyInvocation.MyCommand)`n$errorMessage" -Verbose:$true
}
}
$vmHosts = getVMHosts -vcenter "vcenter"
$counter = 0
foreach($vm in $vmHosts)
{
if($vm -ne $null){$json = ConvertTo-Json $vm -Compress;insertToElasticSearch json $json -info:$true -Verbose:$true}
}
Try ConvertTo-JSON -Depth 1. Sounds like there are properties in the object that have the same name.
I don't have VCenter to verify the script, but I refactored yours a bit to make it more powershell-ly.
Notes:
CmdletBinding gives you -Verbose and other features
Any object not set to a variable is output to the pipeline by default
Return does not do what most developers would expect
function getVMHosts{
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True,Position=1)]
[string]$vcenter,
)
try
{
Write-Verbose "$(get-date -Format "dd/MM/yyyy HH:mm") - Function:$($MyInvocation.MyCommand) - Importing VMWare modules"
Get-Module -ListAvailable -Name "VMware.*" | Import-Module
Write-Verbose "$(get-date -Format "dd/MM/yyyy HH:mm") - Function:$($MyInvocation.MyCommand) - Connecting to Vcenter:$vcenter"
[void]$(Connect-VIServer -Server $vcenter -ErrorAction SilentlyContinue)
Write-Verbose "$(get-date -Format "dd/MM/yyyy HH:mm") - Function:$($MyInvocation.MyCommand) - Getting Data center servers"
Get-Datacenter |
ForEach-Object {
Write-Verbose "$(get-date -Format "dd/MM/yyyy HH:mm") - Function:$($MyInvocation.MyCommand) - Getting VM servers for Data Center:$_"
Get-Datacenter -Name $_.Name |
Get-VM -Verbose:$Verbose|
Select PowerState, Name, NumCpu, MemoryMB, GuestId, VMHost, #{N="IP Address";E={#($_.guest.IPAddress[0])}}
}
Write-Verbose "$(get-date -Format "dd/MM/yyyy HH:mm") - Function:$($MyInvocation.MyCommand) - Disconnecting from VCenter:$vcenter"
[void]Disconnect-VIServer -Server $vcenter -ErrorAction SilentlyContinue -Confirm:$false
}
catch
{
$errorMessage = "$($_.Exception.Message)`n$(($_|select -ExpandProperty invocationinfo).PositionMessage)"
Write-Warning -Message "Exception caught in Function:$($MyInvocation.MyCommand)`n$errorMessage"
}
}
getVMHosts -vcenter "vcenter" |
ForEach-Object {
$json = ConvertTo-Json $_ -Compress;
insertToElasticSearch json $json -info:$true -Verbose:$true
}
}
As noam states there are objects in there causing this. Extract the base case as an example
get-vm <insertexamplevmname> | Select PowerState, Name, NumCpu, MemoryMB, GuestId, VMHost, #{N="IP Address";E={#($_.guest.IPAddress[0])}} | convertto-json -Depth 1
You will see that VMHost isn't just the name of the host it is running on but the actual host object which also has a Name property just like the VM has a Name.
So what you probably want is to extract the VMHost name as you have done for the IP addresses from the guest object.
get-vm <insertexamplevmname> | Select PowerState, Name, NumCpu, MemoryMB, GuestId, #{N="Hostname";E={#($_.VMhost.Name)}}, #{N="IP Address";E={#($_.guest.IPAddress[0])}} | convertto-json
After some fiddling, it appears to be a bug with convertto-json when the get-vm statement returns a single vm object. If more than one vm object is returned, convertto-json works. You can test yourself, replacing vm1 and vm2 with valid vm names:
get-vm -name 'vm1' | convertto-json -depth 1## fail
get-vm -name #('vm1') | convertto-json -depth 1 ## fail
get-vm -name 'vm2' | convertto-json -depth 1 ## fail
get-vm -name #('vm2') | convertto-json -depth 1 ## fail
get-vm -name #('vm1','vm2') | convertto-json -depth 1 ## success
get-vm -name #('vm2','vm1') | convertto-json -depth 1 ## success
One hackaround would be to ensure get-vm always returns two vms by including a known vm, then ignoring the known vm json element. Not recommending this solution, but may help someone in a bind.

Powershell variable is assigned the result of a function AND the parameter I passed to the function

I'm running into this over and over in my script. I have this line of code:
$Errors = Get-DeploymentErrors $uniqueID
When this runs, $Errors is assigned the result of Get-DeploymentErrors and the value of $uniqueID. I just want $Errors to be assigned the result of Get-DeploymentErrors.
Here is the Get-DeploymentErrors function:
Function Get-DeploymentErrors($uniqueID)
{
$Errors = #()
$conn = New-Object -TypeName System.Data.SqlClient.SqlConnection
$conn.ConnectionString = 'removed connection string'
$cmd = New-Object -TypeName System.Data.SqlClient.SqlCommand
$cmd.Connection = $conn
$cmd.CommandText = "removed sql statement"
$cmd.Parameters.AddWithValue("#uniqueID", $uniqueID)
$conn.Open()
$reader = $cmd.ExecuteReader()
if($reader.HasRows)
{
While ($reader.Read())
{
$error = New-Object -TypeName PSObject
$error | Add-Member -MemberType NoteProperty -Name StepID -Value $reader["StepID"]
$error | Add-Member -MemberType NoteProperty -Name DeploymentID -Value $reader["DeploymentID"]
$error | Add-Member -MemberType NoteProperty -Name MessageID -Value $reader["MessageID"]
$error | Add-Member -MemberType NoteProperty -Name Severity -Value $reader["Severity"]
$error | Add-Member -MemberType NoteProperty -Name Message -Value $reader["Message"]
$error | Add-Member -MemberType NoteProperty -Name StepName -Value $reader["StepName"]
$error | Add-Member -MemberType NoteProperty -Name CurrentStep -Value $reader["CurrentStep"]
$error | Add-Member -MemberType NoteProperty -Name TotalSteps -Value $reader["TotalSteps"]
$error | Add-Member -MemberType NoteProperty -Name CurrentTime -Value $reader["CurrentTime"]
$Errors += $error
}
}
return $Errors
}
$cmd.Parameters.AddWithValue() echoes the added parameter, and PowerShell functions return the entire non-captured output on the success output stream, not just the argument of the return keyword.
Quoting from about_Return (emphasis mine):
SHORT DESCRIPTION
Exits the current scope, which can be a function, script, or script block.
LONG DESCRIPTION
The Return keyword exits a function, script, or script block. It can be used to exit a scope at a specific point, to return a value, or to indicate that the end of the scope has been reached.
Users who are familiar with languages like C or C# might want to use the Return keyword to make the logic of leaving a scope explicit.
In Windows PowerShell, the results of each statement are returned as output, even without a statement that contains the Return keyword. Languages like C or C# return only the value or values that are specified by the Return keyword.
Use any of the following methods to suppress the undesired output:
[void]$cmd.Parameters.AddWithValue("#uniqueID", $uniqueID)
$cmd.Parameters.AddWithValue("#uniqueID", $uniqueID) | Out-Null
$cmd.Parameters.AddWithValue("#uniqueID", $uniqueID) > $null
$param = $cmd.Parameters.AddWithValue("#uniqueID", $uniqueID)