arg1I have some code that creates an empty powershell array, then adds items to this array in a do..while loop. For some reason, no matter what I do, the first element in the array is "true". Why is this?
In my code below, you'll notice the loop adds output a line at a time from an external exe. The exe never returns "true", and you can see I'm doing Write-Host for each it that gets added to the array, and there's never a "true" output from this Write-Host call. There is no other code anywhere in my script that adds any elements to the array. This is frustrating because the index of the array is messed up. This essentially makes this array 1-indexed instead of 0-indexed. Does anyone have any ideas about what's happening here?
Also, one more thing to notice, after I initialize the array, i Write-Host the length, and it's 0, then after I'm dont adding all items, the length is what I would expect it to be if "true" were not the first element. So if there's 4 lines returned from the external app, then the second Write-Host $output.Length call will output 4.
Here is my code:
$output = #()
Write-Host "OUTPUT LENGTH START: $($output.Length)" -ForegroundColor Yellow
$continue = $true
do {
$tempoutput = $Process.StandardOutput.ReadLine()
if(($tempoutput -ne $null) -and ([string]::IsNullOrWhiteSpace($tempoutput) -ne $true)) {
Write-Host $tempoutput -ForegroundColor DarkGray
$output += $tempoutput
} else {
$continue = $false
}
}
while($continue -eq $true)
Write-Host "OUTPUT LENGTH END: $($output.Length)" -ForegroundColor Yellow
Also, at the end of my function, i'm returning the output array like this:
$output
And then in my code that calls my function, if I do a foreach over the returned array's elements, "True" will always be the first item in this array.
EDIT TO INCLUDE FULL FUNCTION
Here is my full function with all the Write-Host calls removed:
function Execute-HttpManager($arguments, $filepath){
$ProcessInfo = New-Object System.Diagnostics.ProcessStartInfo
$ProcessInfo.FileName = $filepath
$ProcessInfo.RedirectStandardError = $true
$ProcessInfo.RedirectStandardOutput = $true
$ProcessInfo.RedirectStandardInput = $true
$ProcessInfo.UseShellExecute = $false
$ProcessInfo.CreateNoWindow = $true
$ProcessInfo.Arguments = $arguments
$Process = New-Object System.Diagnostics.Process
$Process.StartInfo = $ProcessInfo
$Process.Start()
$Process.WaitForExit()
$output = #()
$continue = $true
do {
$tempoutput = $Process.StandardOutput.ReadLine()
if(($tempoutput -ne $null) -and ([string]::IsNullOrWhiteSpace($tempoutput) -ne $true)) {
$output += $tempoutput
} else {
$continue = $false
}
}
while($continue -eq $true)
$deployError = $Process.StandardError.ReadToEnd()
$exitcode = $Process.ExitCode
if($exitcode -eq 4) {
$deployagainresponse = Read-Host
if($deployagainresponse -eq 'y') {
Deploy-Database $localapp $localsqlinstance $localdatabasename $localbackup $localsnapshot
} elseif($deployagainresponse -ne 'bypass') {
throw "http interaction failed with error. Check the output."
}
} elseif ($exitcode -ne 0) {
throw "Database deploy failed."
}
return $output
}
And here is the code that calls my function:
$tokenoutput = Execute-HttpManager #("arg1", "arg2", "arg3", "arg4") $pathtoexecutable
It is this $tokenoutput variable that has the "True" added to the beginning of it's array.
Make sure to check for any calls that are returning a value (such as $Process.Start()), and either precede them with [void] or pipe to out-null: $Process.Start() | Out-Null.
Be aware of this for any function! Anything the function outputs is part of the return value.
Related
Trying to use PowerShell to capture the running status of the "Nessus Essentials" software product. Simply trying to capture product status: running, not running, or other. Getting the below error each time. I've tried changing -like to -match and changing string [warn] [scanner] Not linked to a manager to various other shorter versions, with wildcards and without, to no avail. I still get several lines of an ugly error message when all I want is one line with the string Not linked to a manager returned to console with nothing beneath that.
Pertinent snippet working incorrectly:
} elseif(($agentStatus.stdOut -like "[warn] [scanner] Not linked to a manager")) {
Throw "Not linked to a manager"
The Error:
The Code:
Function Start-ProcessGetStreams {
[CmdLetBinding()]
Param(
[System.IO.FileInfo]$FilePath,
[string[]]$ArgumentList
)
$pInfo = New-Object System.Diagnostics.ProcessStartInfo
$pInfo.FileName = $FilePath
$pInfo.Arguments = $ArgumentList
$pInfo.RedirectStandardError = $true
$pInfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pInfo.CreateNoWindow = $true
$pInfo.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden
$proc = New-Object System.Diagnostics.Process
$proc.StartInfo = $pInfo
Write-Verbose "Starting $FilePath"
$proc.Start() | Out-Null
Write-Verbose "Waiting for $($FilePath.BaseName) to complete"
$proc.WaitForExit()
$stdOut = $proc.StandardOutput.ReadToEnd()
$stdErr = $proc.StandardError.ReadToEnd()
$exitCode = $proc.ExitCode
Write-Verbose "Standard Output: $stdOut"
Write-Verbose "Standard Error: $stdErr"
Write-Verbose "Exit Code: $exitCode"
[PSCustomObject]#{
"StdOut" = $stdOut
"Stderr" = $stdErr
"ExitCode" = $exitCode
}
}
Function Get-NessusStatsFromStdOut {
Param(
[string]$stdOut
)
$stats = New-Object System.Collections.Hashtable
$StdOut -split "`r`n" | % {
if($_ -like "*:*") {
$result = $_ -split ":"
$stats.add(($result[0].Trim() -replace "[^A-Za-z0-9]","_").ToLower(),$result[1].Trim())
}
}
Return $stats
}
Function Get-DateFromEpochSeconds {
Param(
[int]$seconds
)
$utcTime = (Get-Date 01.01.1970)+([System.TimeSpan]::fromseconds($seconds))
Return Get-Date $utcTime.ToLocalTime() -Format "yyyy-MM-dd HH:mm:ss"
}
Try {
$nessusExe = Join-Path $env:ProgramFiles -ChildPath "Tenable\Nessus\nessuscli.exe" -ErrorAction Stop
} Catch {
Throw "Cannot find NessusCli.exe"
}
Write-Host "Getting Agent Status..."
$agentStatus = Start-ProcessGetStreams -FilePath $nessusExe -ArgumentList "managed status"
If($agentStatus.stdOut -eq "" -and $agentStatus.StdErr -eq "") {
Throw "No Data Returned from NessusCli"
} elseif($agentStatus.StdOut -eq "" -and $agentStatus.StdErr -ne "") {
Throw "StdErr: $($agentStatus.StdErr)"
} elseif(($agentStatus.stdOut -like "[warn] [scanner] Not linked to a manager")) {
Throw "Not linked to a manager"
} elseif(-not($agentStatus.stdOut -like "*Running: *")) {
Throw "StdOut: $($agentStatus.StdOut)"
} else {
$stats = Get-NessusStatsFromStdOut -stdOut $agentStatus.StdOut
If($stats.last_connection_attempt -as [int]) { $stats.last_connection_attempt = Get-DateFromEpochSeconds $stats.last_connection_attempt }
If($stats.last_connect -as [int]) { $stats.last_connect = Get-DateFromEpochSeconds $stats.last_connect }
If($stats.last_scanned -as [int]) { $stats.last_connect = Get-DateFromEpochSeconds $stats.last_scanned }
}
$stats | Out-Host
Note: Code above is courtesy of here, I've only made a change to the path of Nessus, and I am adding the attempt to capture that it's not connected to a manager.
Modify your code so that it separates standard output from error and so that it handles each line separately.
The following is how to capture standard output (excluding else statements and error handling) of a program (according to your $Proc variable)
if ($proc.Start())
{
while (!$proc.StandardOutput.EndOfStream)
{
$StreamLine = $proc.StandardOutput.ReadLine()
if (![string]::IsNullOrEmpty($StreamLine))
{
# TODO: Duplicate code in this scope as needed or rewrite to use multiline regex
$WantedLine = [regex]::Match($StreamLine, "(?<wanted>.*Not linked to a manager.*)")
$Capture = $WantedLine.Groups["wanted"]
if ($Capture.Success)
{
Write-Output $Capture.Value
}
}
}
}
After that deal with error output separately:
$StandardError = $Proc.StandardError.ReadToEnd()
if (![string]::IsNullOrEmpty($StandardError))
{
# Or use Write-Error
Write-Output $StandardError
}
Working on a script to get the status of Windows Defender components. Running into a challenge looping through the results from Get-MpComputerStatus as I'm wanting to write out which components are enabled and disabled.
The issue that I'm running into is I'm not able to get the specific value from the PSOBJECT and only get everything.
#Microsoft Defender Statuses
$DefenderStatus = Get-MpComputerStatus | select-object AMServiceEnabled, AntispywareEnabled, AntivirusEnabled, BehaviorMonitorEnabled, IoavProtectionEnabled, IsTamperProtected, IsVirtualMachine, NISEnabled, OnAccessProtectionEnabled, RealTimeProtectionEnabled
#Write results to a PSOBJECT
$result = ([ordered]#{
'Anti-Virus'=$DefenderStatus.AntivirusEnabled
'Anti-Malware'=$DefenderStatus.AMServiceEnabled
'Anti-Spyware'=$DefenderStatus.AntispywareEnabled
'Behavior Monitor'=$DefenderStatus.BehaviorMonitorEnabled
'Office-Anti-Virus'=$DefenderStatus.IoavProtectionEnabled
'NIS'=$DefenderStatus.NISEnabled
'Access Protection'=$DefenderStatus.OnAccessProtectionEnabled
'R-T Protection'=$DefenderStatus.RealTimeProtectionEnabled
})
foreach ($Status in $result)
{
If ($Status.Values -eq $false)
{
Write-Host "$Status.Keys is Disabled"
$Disabled = $Disabled + ", " + $Status
}
Else
{
Write-Host "$Status.Keys is Enabled"
$Enabled = $Enabled + ", " + $Status
}
}
As Theo comments, you're storing the results in an ordered hash table, if you want to iterate over the Key-Value pairs you could use .GetEnumerator() or .Keys property or .get_Keys() method, for example:
$result = [ordered]#{
'Anti-Virus' = $true
'Anti-Malware' = $true
'Anti-Spyware' = $false
'Behavior Monitor' = $false
'Office-Anti-Virus' = $true
'NIS' = $false
'Access Protection' = $true
'R-T Protection' = $true
}
foreach($pair in $result.GetEnumerator()) {
# If the Value is $true
if($pair.Value) {
"{0} is Enabled" -f $pair.Key
continue
}
# If we're here last condition was $false
"{0} is Disabled" -f $pair.Key
}
However, since $DefenderStatus seem to be an object you could also do the following (if it was an object[] (array of objects) this would need to be changed):
$DefenderStatus = [PsCustomobject]#{
'Anti-Virus' = $true
'Anti-Malware' = $true
'Anti-Spyware' = $false
'Behavior Monitor' = $false
'Office-Anti-Virus' = $true
'NIS' = $false
'Access Protection' = $true
'R-T Protection' = $true
}
foreach($object in $DefenderStatus.PSObject.Properties) {
# Property Value
if($object.Value) {
"{0} is Enabled" -f $object.Name # Property Name
continue
}
"{0} is Disabled" -f $object.Name
}
I'm not sure what to search for to solve this one. I have a scope/persistence of data issue, where a variable used to populate my data structure is over-writing other items in the data structure (ImageFileName). This is my code:
###Functions...first two are just for info
#method to get messages for mdb files
#dependency-Need to download accessDatabaseEngine(64 bit) redestributable: https://www.microsoft.com/en-us/download/details.aspx?id=54920
Function ProcessHelpMDB{
[cmdletbinding()]
Param ([string]$mdbLookupError, [string]$mdbFilePath, [string]$mdbDeviceSeries) #$mdbLookupError = error number, like 701. $mdbDeviceSeries is 1000
Process
{
#Write-Host "mdbLookupString: $mdbLookupString" -ForegroundColor Cyan
$adOpenStatic = 3
$adLockOptimistic = 3
#Write-Host "In ProcessMDB" -ForegroundColor darkRed
#$pathViewBase = 'C:\me\EndToEnd_view\' #View dir. Maybe param later
#$pathToMdb = Join-Path -Path $pathViewBase -ChildPath $mdbFileName
$deviceTable = $mdbDeviceSeries + "PP"
$mdbLookupError -Match '[0-9]*-([0-9]*)'
$errLookup = $Matches[1]
#Write-Host "dps" -ForegroundColor DarkMagenta
$selectQuery = “SELECT [$($deviceTable)].[HelpCode],
[$($deviceTable)].[ScreenNumber],
[$($deviceTable)].[TextID],
[$($deviceTable)].[PictureID]
FROM [$($deviceTable)]
WHERE
[$($deviceTable)].[HelpCode] = $($errLookup)"
$cn = new-object -comobject ADODB.Connection
$rs = new-object -comobject ADODB.Recordset
$cn.Open("Provider = Microsoft.ACE.OLEDB.16.0;Data Source = $mdbFilePath")
$rs.Open($selectQuery,
$cn, $adOpenStatic, $adLockOptimistic)
$i=0
$ret = [System.Collections.Generic.List[psobject]]::new()
if($rs.EOF)
{
Write-Host "$mdbLookupString not in $mdbFileName...record set returned emtpy for query"
}#if
else
{
while($rs.EOF -ne $True)
{
$result = [ordered]#{}
#$hash = #{}
foreach ($field in $rs.Fields)
{
$result[$field.name] = $field.Value
}#result
$newObject = [PSCustomObject]$result
$ret.Add($newObject) #
$rs.MoveNext()
} #while
}#else
Write-Host "retArr[0] $($ret[0])" #prints retArr[0] #{PictureID=HELP_...; TextID=HELP_...; HelpCode=9; ScreenNumber=1}
$i=0
foreach($row in $ret) #goes thru all rows
{
Write-Host "retArr[0] $($ret[$i,"TextID"])" #prints retArr[0] #{HelpCode=9; ScreenNumber=1; TextID=HELP_...; PictureID=HELP_...}
####
Write-Host "retArr[] $($row)" #prints retArr[] #{HelpCode=9; ScreenNumber=1; TextID=HELP_...; PictureID=HELP_7000_POWER_COVER_RIBBON}
Write-Host "retArr[0] $($row[$i])" #prints retArr[0] #{HelpCode=9; ScreenNumber=1; TextID=HELP_...; PictureID=HELP_...}
$i++
}
foreach($row in $ret.GetEnumerator()) #this is working for each row
{
Write-Host $row.TextID #prints HELP_...
Write-Host $row.'TextID' #prints HELP_...
}
$ret | ForEach-Object {
Write-Host TextID= $($_.TextID) #prints TextID= HELP_...
Write-Host TextID= $($_.'TextID') #prints TextID= HELP_...
} #
$cn.Close()
return $ret #Items queried from db ################################################# need to put them in excel file in order next
} #end Process
}# End of Function process mdb's
#This function gets mdb info out and returns English-US message found
Function ProcessK_MDB{
[cmdletbinding()]
Param ([string]$mdbLookupstring) #$mdbLookupString like HELP_...
Process
{
$adOpenStatic = 3
$adLockOptimistic = 3
$pathViewBase = 'C:\me\\EndToEnd_view\' #View dir. Maybe param later
$mdbFileNamePath = 'KAppText.mdb'
$pathToMdb = Join-Path -Path $pathViewBase -ChildPath $mdbFileNamePath
if(Test-Path $pathToMdb)
{
$selectQuery = “SELECT [Messages].[Message Description],
[Messages].[English - Us]
FROM [Messages]
WHERE [Messages].[Message Description] = '$($mdbLookupString)'”
$cn = new-object -comobject ADODB.Connection
$rs = new-object -comobject ADODB.Recordset
$cn.Open("Provider = Microsoft.ACE.OLEDB.16.0;Data Source = $pathToMdb")
$rs.Open($selectQuery,
$cn, $adOpenStatic, $adLockOptimistic)
if($rs.EOF) #empty
{
Write-Host "$mdbLookupString not in $mdbFileName...record set returned emtpy for query"
$ret = ""
}#if
else #got results
{
$returnArr = $rs.GetRows()
#$ret = $returnArr[0,1]
#$ret2 = $returnArr[1,1]
$ret = $returnArr[1,0] #has long text
#$ret4 = $returnArr[0,0] #has short text
#Write-Host $ret
}#else got results
$cn.Close()
} #testPath
else {
Write-Host "$pathToMdb does not exist"
}
return $ret #Message English-US for parameter/Message Description given
} #end Process
}# End of Function process mdb's
Function Get-ImageName{
[cmdletbinding()]
Param ([string]$imageName, [string]$fileNamePath)
Process
{
#find image file name to look for
[System.String] $pictureName = ""
if($imageName -Match "HELP")
{
#remove "HELP" part of file name
$($row.PictureID) -Match "HELP_(.*)" #get the part after HELP_
Write-Host $Matches[0]
Write-Host $Matches[1]
$pictureName = $Matches[1]
}
else {
$pictureName = $imageName
}
$imageFile2 = Get-ChildItem -Recurse -Path $ImageFullBasePath -Include #("*.bmp","*.jpg","*.png") | Where-Object {$_.Name -match "$($pictureName)"} #$imageFile | Select-String -Pattern '$($pictureName)' -AllMatches
Write-Host "ImageFile2: $($imageFile2)"
$imgFile = ""
foreach($imgFile in $imageFile2) #there may be more than one...just get last one...there are multiple telephone images
{
if($imgFile.Exists) #if($imageFile2.Exists)
{
#$image = [System.Drawing.Image]::FromFile($imgFile) #may not need this step
#need to figure out which is correct if there's multiple images
return $imgFile
}
else {
Write-Host "$($imgFile) does not exist"
return $null
}
} #foreach imageFile2
return $null
} #end Process
}# End of Function process mdb's
###main####
$resultHelp = ProcessHelpMDB -mdbLookupError $errCode -mdbFilePath $basePathFull -mdbDeviceSeries $deviceVer #######
$result = foreach($row in $resultHelp.GetEnumerator()) #this is working for each row
{
if($row -ne $True) #not sure why it adds true at the top
{
Write-Host $row.TextID #prints HELP_...
#lookup value from kapptext.mdb
Write-Host $($row.TextID) #prints nothing but looks ok in next function
$longText = ProcessK_MDB -mdbLookupstring $($row.TextID) #gives English-US message from device for parameter given
#insert images######################
#I can see that these are assigned correctly and returned from Function:
[System.Drawing.Image] $image = New-Object System.Drawing.Image #error...see Update2
[System.String] $imageNamePath = New-Object System.String #error...see Update2
[System.String] $imageNamePath = Get-ImageName -imageName $($row.PictureID) -fileNamePath $ImageFullBasePath
if($null -ne $imageNamePath)
{
$image = Get-Image -imageFileName $imageNamePath
}
else
{
Write-Host "Did not find an image file for $($row.PictureID) in $ImageFullBasePath"
}
#get the data ready to put in spreadsheet
New-Object psobject -Property $([ordered]#{
ScreenNumber = $($row.ScreenNumber)
KPMKey = $($row.TextID)
EnglishUS = $($longText)
PictureID = $($row.PictureID)
ImageFound = ""
ImageFileName = $($imageNamePath) ###???this is over-written...all same in $result after done with loop
})
} #if not true
} #foreach row $resultHelp
##note: $image gets inserted in the spreadsheet later, but since the names aren't showing correctly when use $results, I'm not sharing that part.
I can see after this runs for the 9 rows, that each ImageFileName is the same in $result. How do I do this so it maintains what is returned from the method? Right now I am trying New-Object, but it didn't fix the issue.
This is what $resultHelp looks like:
[0] $true (I'm not sure why it puts true at the top) [1]
#(HelpCode=9;ScreenNumber=1;TextID=HELP_...JA;PictureID=HELP_...RIB)
[2]
#(HelpCode=9;ScreenNumber=2;TextID=HELP_...ROLL;PictureID=HELP_...ROLL)
[3]
#(HelpCode=9;ScreenNumber=3;TextID=HELP_...EDGE;PictureID=HELP_...UT)
...
I am using Powershell 5.1 and VSCode.
Update:
I checked again, and in Get-ImageName, it's returning a file name like "Contact_Service"...bmp and it looks like it's getting put in the psObject ImageFileName...($imageNamePath), and the same thing for the other images found. When I look in the end, $result has all the same values for that ImageFileName. and the one that used to say "Contact_Service"..bmp is something else now, matching the other ones in $result.
Update2:
There are a couple errors:
New-Object : A constructor was not found. Cannot find an appropriate
constructor for type System.Drawing.Image
and
New-Object : A constructor was not found. Cannot find an appropriate
constructor for type System.String.
for where I tried dealing with the object over-write issue in the main code
Update3:
After I get the psobject in good shape, I put it in a spreadsheet with Export-Excel. I just wanted to give this info so you know why I'm putting it in the psobject like that:
$xlsx = $result | Export-Excel -Path $outFilePath -WorksheetName $errCode -Autosize -AutoFilter -FreezeTopRow -BoldTopRow -PassThru # -ClearSheet can't ClearSheet every time or it clears previous data
I figured it out.
the problem was that even though I was finding different $imageNamePaths for to assign to the Property as ImageFileName for each PictureID, and assigning those properties in the psobject in the foreach loop, I wound up with the same thing for each ImageFileName property (overwritten). This fixed it.
New-Object psobject -Property $([ordered]#{
ScreenNumber = $($row.ScreenNumber)
KPMKey = $($row.TextID)
EnglishUS = $($longText)
PictureID = $($row.PictureID)
ImageFound = ""
ImageFileName = "$($imageNamePath)" ####added double quotes
})
The double quotes let the different $imageNamePath values remain instead of being over-written. I'm not exactly sure why.
And thank you #Mathias, I will suppress output from my -Match to see if the $true is removed at the top of my data returned from the Function. :)
I'm working on a PowerShell script for some work use, and am having trouble getting a function it's data directly to a variable. Below is the function and my test:
function validateInput {
Param(
[string]$Text = 'Put text here'
)
do {
try {
$numOk = $true
$GetMyANumber = Read-Host "$text"
if ($GetMyANumber -gt 3){
$numOK = $false
}
} catch {
$numOK = $false
}
if ($numOK -ne $true) {
cls
Write-Host "Please enter a valid number" -Foreground Red
}
} until (($GetMyANumber -ge 0 -and $GetMyANumber -le 3) -and $numOK)
}
$firstName = validateInput($firstNamePrompt)
$lastName = validateInput ($lastNamePrompt)
Write-Host "First name length is $firstname"
Write-Host "Last name length is $lastname"
My understanding is that the in the last few lines, the function SHOULD assign it's output to the variables $firstName and $lastName, but I output that, they are blank. I'm sure I'm missing something obvious here, but can anyone let me know what I'm screwing up?
I have a little trouble understanding the way to implement this process. I want to achieve a total count in the score so that if a test successfully passes or fails it can be added into an array. That array will be counted in the length.
This is my code as an example:
#This stores the array of the number of passed and failed test
$passed = #()
$failed = #()
Describe "Template Syntax" {
It "Has a JSON template" {
$fileLocation = "$here\azuredeploy.json"
$fileCheck = $fileLocation | Test-Path
if ($fileCheck -eq $true) { $passed = $passed + 1
Write-Host "1st file exist " }
if ($fileCheck -eq $false) { $failed = $failed + 1
Write-Host "1st file does exist" }
}
It "Has a parameters file" {
$fileLocation ="$here\azuredeploy.parameters*.json"
$fileCheck = $fileLocation | Test-Path
if ($fileCheck -eq $true) { $passed = $passed + 1;
Write-Host "2nd file exist "}
if ($fileCheck -eq $false) { $failed = $failed + 1
Write-Host "2nd file does exist" }
}
PrintArgs
}
function PrintArgs(){
Write-Host -ForegroundColor yellow "Passed: $($passed.Length) Failed: $($failed.Length)"
}
Is there a different way or another approach that I can do to achieve this? I know that pester does it automatically, however, I want to use a Powershell script to test.
Your Pester tests aren't really Pester tests unless you include a Should assertion. I think you should rewrite your tests as follows:
Describe "Template Syntax" {
$fileLocation = "$here\azuredeploy.json"
$fileCheck = $fileLocation | Test-Path
It "Has a JSON template" {
$fileCheck | Should -Be $true
}
$fileLocation ="$here\azuredeploy.parameters*.json"
$fileCheck = $fileLocation | Test-Path
It "Has a parameters file" {
$fileCheck | Should -Be $true
}
}
If you then run this with Invoke-Pester you get a summary of passed and failed test counts at the end automatically. If you need to access these values, you can use -PassThru to return them to a variable. For example:
$Results = Invoke-Pester .\your.tests.ps1 -PassThru
Then you can get the number of passed and failed tests as follows:
$Results.PassedCount
$Results.FailedCount
If you genuinely want to use your own counters (which would mean maintaining lots of unnecessary logic) you could do as follows:
$Passed = 0
$Failed = 0
Describe "Template Syntax" {
$fileLocation = "$here\azuredeploy.json"
$fileCheck = $fileLocation | Test-Path
It "Has a JSON template" {
$fileCheck | Should -Be $true
}
if ($fileCheck -eq $true) { $Passed++ } else { $Failed++ }
$fileLocation ="$here\azuredeploy.parameters*.json"
$fileCheck = $fileLocation | Test-Path
It "Has a parameters file" {
$fileCheck | Should -Be $true
}
if ($fileCheck -eq $true) { $Passed++ } else { $Failed++ }
Write-Host -ForegroundColor yellow "Passed: $Passed Failed: $Failed"
}
Note that the Describe block acts as a kind of script scope, so you have to print the values of $Passed and $Failed within the Describe to get at the values.
Looking at your code, you do not need arrays to count the scores.
Instead of defining $passed and $failed as arrays, just set them up as integer counters with a starting value of 0
$passed = $failed = 0
Then instead of calling function PrintArgs() you simply do
Write-Host -ForegroundColor yellow "Passed: $passed Failed: $failed"
By the way, to increment a counter you can simply do $passed++ instead of $passed = $passed + 1
If you DO insist on using arrays you can change the $passed = $passed + 1 to something like $passed += $true. By doing that you add a new element to the array with a value of $true (or whatever you feel is more appropriate.