Output true value for Foreach statement - powershell

I am trying to output the value which checks if the condition matches, but instead its returning value whether it is true or not.
$result = "VM name"
$name= get-content C:\monitor\Serverlist\Serverlist2.txt
foreach($nam1 in $name)
{
#Write-output $nam1
$l=Get-Vm -computername $nam1 |out-string
foreach ($l2 in $l)
{
if ( $l2 = $result )
{
Write-Output $input "is in" $nam1
}
else
{
""
}
}
}
but output i am getting is true in all case, where as VM name is present in comp1 only.
VM name is in comp1
VM name is in comp2
VM name is in comp3
If statement should return condition if it matches? I also tried looping if statement outside 1st foreach loop but that gives me result of last comp "comp3" even the matching result is in comp1.
Any Idea where I am going wrong?

The = sign not for conditional testing, it's for setting the value:
if ( $l2 = $result )
{
Write-Output $input "is in" $nam1
}
Should be... (note that I'm using -eq to test equality)
if ( $l2 -eq $result )
{
Write-Output $input "is in" $nam1
}
But even that wouldn't work. Your conditional test between a string and a VirtualMachine object won't work. Here's what you want...
if ( $l2.Name -eq $result )
{
Write-Output $input "is in" $nam1
}
In the above snippet, I'm doing a conditional test on VirtualMachine.Name (type string) with your variable.

Related

Powershell Write-Output strange behavior

I have a script below that behaves really strangely.
For the first case I try to return an empty list specifying -NoEnumarate flag. But for some reason, the function returns $null
For the second case I do precisely the same as for the first case with the only difference: rather than providing -InputObject as a positional parameter, I provide it explicitly.
Why in the first case I get $null and in the second case I get the expected result - empty List[string]. I'm really confused.
# case 1
function Foo {
$result = [System.Collections.Generic.List[string]]::new()
Write-Output -InputObject $result -NoEnumerate
}
$foo = Foo
if ($foo -is [System.Collections.Generic.List[string]]) {
Write-Host 'Foo'
}
if ($null -eq $foo) {
Write-Host '$foo is null. Whyyy?'
}
# case 2
function Bar {
$result = [System.Collections.Generic.List[string]]::new()
Write-Output $result -NoEnumerate
}
$bar = Bar
if ($bar -is [System.Collections.Generic.List[string]]) {
Write-Host '$bar is list[string]'
}

Powershell: Arrays index acess and check if previous is substring to next

I need to link the job to the subjob: the job is of this format for example ACGN100Q while the subjobs that are attached are sequential and of this format: ACGN-100Q-000T;ACGN-100Q-010T;ACGN-100Q-020T;ACGN-100Q-030T
In my csv file the type of this job ACGN100Q is "TechnologyInteraction" while the subjobs are of type "TechnologyService". I am developing a script that allows me to say for example that the link between ACGN-100Q-000T and ACGN-100Q-010T is of type "TrigerringRelation" and the link between ACGN100Q and ACGN-100Q-000T is of type "RealizationRelation". I need help because I can't make the link.
Here is my starting csv file :
newElements.csv
ID,"Type","Name","Documentation"
eb214110-2b6a-48b2-ba5a-7c13dc3bba39,"TechnologyInteraction","ACGN100Q","Begin Of JobStream"
a46681e7-19a8-4fc5-b747-09679c15ff26,"TechnologyService","ACGN-100Q-000T","Transfert UDM (xACGN000)"
85761a09-1145-4037-a527-66a743def45f,"TechnologyService","ACGN-100Q-010T","move fichier REF to work"
27b126fb-c708-427d-b0a6-ce4747114ac4,"TechnologyService","ACGN-100Q-020T","w_read_account"
bb0c5e42-5fad-4bd9-8ee9-f41d0b824e82,"TechnologyService","ACGN-100Q-030T","w_read_referential"
0b8b76e3-62fa-4527-9f05-2eb4dbaa8e97,"TechnologyService","ACGN-100Q-040T","w_load_CompanyGroup"
1f487986-3cac-4af8-bda2-6400a1c71f48,"TechnologyService","ACGN-100Q-050T","w_load_Company"
And I want to get a file that looks like this:
relation.csv
"ID","Type","Name","Documentation","Source","Target"
"New ID","RealizationRelationship","","","eb214110-2b6a-48b2-ba5a-7c13dc3bba39","a46681e7-19a8-4fc5-b747-09679c15ff26"
"New ID","TriggeringRelationship","","","a46681e7-19a8-4fc5-b747-09679c15ff26","85761a09-1145-4037-a527-66a743def45f"
"New ID","TriggeringRelationship","","","85761a09-1145-4037-a527-66a743def45f","27b126fb-c708-427d-b0a6-ce4747114ac4"
"New ID","TriggeringRelationship","","","27b126fb-c708-427d-b0a6-ce4747114ac4","bb0c5e42-5fad-4bd9-8ee9-f41d0b824e82"
"New ID","TriggeringRelationship","","","bb0c5e42-5fad-4bd9-8ee9-f41d0b824e82","0b8b76e3-62fa-4527-9f05-2eb4dbaa8e97"
"New ID","TriggeringRelationship","","","0b8b76e3-62fa-4527-9f05-2eb4dbaa8e97","1f487986-3cac-4af8-bda2-6400a1c71f48"
$result= #()
function linkedRelationCsvToElementsCsv{
#relations.csv headers are ID,"Type","Name","Documentation","Source","Target"
$Type=#()
$Name=#()
$ID=#()
$Documentation=#()
#$pattern="^(WEBX|DWHS|COGN|CLOT|CLAI|BTRE|BISI|BDDO|ARXL|AGSO|AGPC|ACTO|FNET|ARX|AGS|INF|CLA|MEM|SWA|REX)-"
$newElementsCsv=Import-CSV $env:USERPROFILE\Desktop\Archi\newElements.csv |sort ID,"Type","Name","Documentation" -Unique
# Check if type is TechnologyInteraction or TechnologyService and link :TechnologyService to TechnologyInteraction and TechnologyInteraction to TWS id's
ForEach ($line in $newElementsCsv){
$Type += $line.Type
$Name += $line.Name
$ID +=$line.ID
$Documentation += $_.Documentation
#Search for element type in elements.csv
for( $index=0; $index -le $Name.length-1; $index++){
if($Type[$index] -eq 'TechnologyInteraction' -or $Type[$index] -eq 'TechnologyEvent' ){
Write-Warning "Case type TechnologyInteraction founded, new type of RealizationRelationship created "
# if the job is of type "TechnologyInteraction" or "TechnologyEvent", we link it to the TWS id's(TechnologyCollaboration,ef2f510b-924b-439d-8720-0183c7294eb3) in archi.
$newArrayResult= New-Object PsObject -Property #{ID=[guid]::NewGuid().ToString(); "Type"="RealizationRelationship"; "Name"=$Name[$index]; "Documentation"=$Documentation[$index]; "Source"="ef2f510b-924b-439d-8720-0183c7294eb3"; "Target"=$ID[$index]}
$result = $result + $newArrayResult
}elseif ($Type[$index][0].Type -eq 'TechnologyService' -and$Type[$index][1].Type -eq 'TechnologyService' ){
Write-Warning "Case type TechnologyService founded, new type of TriggeringRelationship created "
$newArrayResult2 = New-Object PsObject -Property #{ID=[guid]::NewGuid().ToString(); "Type"="TriggeringRelationship"; "Name"=""; "Documentation"=""; "Source"=$line[$index][0].ID; "Target"=$line[$index][1].ID}
$result = $result + $newArrayResult2
}
}
}
$result |Select-Object -Property ID,"Type","Name","Documentation","Source","Target"| Export-Csv $env:USERPROFILE\Desktop\Archi\relation.csv -NoTypeInformation -Encoding UTF8
}linkedRelationCsvToElementsCsv # Call the function
> the elseIf() not return value.
Thanks you in advance.
The following code generates exactly the output you want for exactly the input you've given. There might be unexpected edge cases, so you should write some tests (e.g. with Pester) to confirm it behaves how you want it to in those edge cases.
The key is that the output for any row includes the ID of the previous row as well as the current row, so we keep the previous row in a variable during the foreach loop so we can inspect it when we process the next row, and the Type in the output just depends on the Type of the previous row.
Note that I've also moved the conversion to / from csv out of the main function so it's easier to unit test the function in isolation.
function ConvertTo-ElementItems
{
param
(
[object[]] $Relations
)
$jobTypes = #( "TechnologyInteraction", "TechnologyEvent" );
$subTypes = #( "TechnologyService" );
$previousItem = $null;
foreach( $item in $Relations )
{
if( $item.Type -in $jobTypes )
{
# start of a new job, but don't output anything
}
elseif( $item.Type -notin $subTypes )
{
# not a subjob type that we recognise
throw "unrecognised subjob type '$($item.Type)' for subjob '$($item.ID)'";
}
elseif( $null -eq $previousItem )
{
# we've got a subjob, but there was no previous job or subjob
throw "no preceding item for subjob '$($item.ID)'";
}
elseif( $previousItem.Type -in $jobTypes )
{
# this is the first subjob after the parent job
new-object PSCustomObject -Property ([ordered] #{
"ID" = "New ID"
"Type" = "RealizationRelationship"
"Name" = "";
"Documentation" = ""
"Source" = $previousItem.ID
"Target" = $item.ID
});
}
else
{
# the preceding item was a subjob as well
new-object PSCustomObject -Property ([ordered] #{
"ID" = "New ID"
"Type" = "TriggeringRelationship"
"Name" = ""
"Documentation" = ""
"Source" = $previousItem.ID
"Target" = $item.ID
});
}
$previousItem = $item;
}
}
And here's an example of using the function:
$ErrorActionPreference = "Stop";
Set-StrictMode -Version "Latest";
$inputCsv = #"
ID,"Type","Name","Documentation"
eb214110-2b6a-48b2-ba5a-7c13dc3bba39,"TechnologyInteraction","ACGN100Q","Begin Of JobStream"
a46681e7-19a8-4fc5-b747-09679c15ff26,"TechnologyService","ACGN-100Q-000T","Transfert UDM (xACGN000)"
85761a09-1145-4037-a527-66a743def45f,"TechnologyService","ACGN-100Q-010T","move fichier REF to work"
27b126fb-c708-427d-b0a6-ce4747114ac4,"TechnologyService","ACGN-100Q-020T","w_read_account"
bb0c5e42-5fad-4bd9-8ee9-f41d0b824e82,"TechnologyService","ACGN-100Q-030T","w_read_referential"
0b8b76e3-62fa-4527-9f05-2eb4dbaa8e97,"TechnologyService","ACGN-100Q-040T","w_load_CompanyGroup"
1f487986-3cac-4af8-bda2-6400a1c71f48,"TechnologyService","ACGN-100Q-050T","w_load_Company"
"#
$expectedCsv = #"
"ID","Type","Name","Documentation","Source","Target"
"New ID","RealizationRelationship","","","eb214110-2b6a-48b2-ba5a-7c13dc3bba39","a46681e7-19a8-4fc5-b747-09679c15ff26"
"New ID","TriggeringRelationship","","","a46681e7-19a8-4fc5-b747-09679c15ff26","85761a09-1145-4037-a527-66a743def45f"
"New ID","TriggeringRelationship","","","85761a09-1145-4037-a527-66a743def45f","27b126fb-c708-427d-b0a6-ce4747114ac4"
"New ID","TriggeringRelationship","","","27b126fb-c708-427d-b0a6-ce4747114ac4","bb0c5e42-5fad-4bd9-8ee9-f41d0b824e82"
"New ID","TriggeringRelationship","","","bb0c5e42-5fad-4bd9-8ee9-f41d0b824e82","0b8b76e3-62fa-4527-9f05-2eb4dbaa8e97"
"New ID","TriggeringRelationship","","","0b8b76e3-62fa-4527-9f05-2eb4dbaa8e97","1f487986-3cac-4af8-bda2-6400a1c71f48"
"#;
$relations = $inputCsv | ConvertFrom-Csv;
$elements = ConvertTo-ElementItems -Relations $relations;
$outputCsv = ($elements | ConvertTo-Csv -NoTypeInformation) -join "`n";
if( $outputCsv -ne $expectedCsv )
{
throw "output csv doesn't match expected csv";
} else {
write-host "output csv matches expected csv";
}

How to add items to an array in a function as a script variable on Powershell?

I am trying to add items to an array variable that I am declaring outside of a function.
Here is the idea of my code in a very simplified way:
function Test($NAME, $SPEED){
$fName = "testName"
$fSpeed = 100
if($status = ($fName -eq $NAME) -and ($fSpeed -eq $SPEED))
{}
else{
if($fName -ne $NAME)
{$errorMessages += "The name is not" + $NAME}
if($fSpeed -ne $SPEED)
{$errorMessages += "The speed is not" + $SPEED}
}
return $status
}
$script:errorMessages=#()
$result=#()
$result += Test -NAME "alice" -SPEED "100"
$result += Test -NAME "bob" -SPEED "90"
#result is an array of booleans that I need later on
$errorMessages
When I display $errorMessages, this is the expected output that I'd like:
The name is not alice
The name is not bob
The speed is not 90
However, when I try to display the variable outside of the function, and even outside of the "else" block, I get nothing printed out. How can I correctly add the error messages to the array?
You want to call errorMessages via the script scope. Therefore you've to use $script:errorMessage (instead of $errorMessage) inside your function.
function Test($NAME, $SPEED) {
$fName = "testName"
$fSpeed = 100
$status = ($fName -eq $NAME) -and ($fSpeed -eq $SPEED)
if (!$status) {
if ($fName -ne $NAME) {
$script:errorMessages += "The name is not" + $NAME
}
if ($fSpeed -ne $SPEED) {
$script:errorMessages += "The speed is not" + $SPEED
}
}
$status
}
$errorMessages = #()
$result = #()
$result += Test -NAME "alice" -SPEED "100"
$result += Test -NAME "bob" -SPEED "90"
#result is an array of booleans that I need later on
$errorMessages
Now you get the expected output:
The name is notalice
The name is notbob
The speed is not90
Also be aware about the return statement in PowerShell -> stackoverflow answer
Hope that helps

Inconsistent behavior in powershell with null parameters

I need to write a function in powershell that tells apart a 'parameter not being passed' from one passed with string empty (or any other string)
I wrote it like this:
function Set-X {
param(
[AllowNull()][string]$MyParam = [System.Management.Automation.Language.NullString]::Value
)
if ($null -ne $MyParam) { write-host 'oops' }
else { write-host 'ok' }
}
If I call Set-X without parameters from ISE, it works as I expect and prints 'ok'.
But if I do that from the normal console, it prints 'oops'.
What is going on? What is the proper way to do it?
Allowing the user to pass in a parameter argument value of $null does not change the fact that powershell will attempt to convert it to a [string].
Converting a $null value in powershell to a string results in an empty string:
$str = [string]$null
$null -eq $str # False
'' -eq $str # True
(same goes for $null -as [string] and "$null")
Remove the type constraint on the MyParam parameter if you not only want to allow $null but also accept $null as a parameter value:
function Set-X {
param(
[AllowNull()]$MyParam = [System.Management.Automation.Language.NullString]::Value
)
if ($null -ne $MyParam) { write-host 'oops' }
else { write-host 'ok' }
}
As Mathias and BenH have written, the culprit is casting $null to the [string] type, which results in an empty string:
[string]$null -eq '' #This is True
But for the sample code in Mathias answer to work correctly we also have to replace
[System.Management.Automation.Language.NullString]::Value
with $null
function Set-X {
param(
[AllowNull()]$MyParam = $null
)
if ($null -ne $MyParam) { write-host 'oops' }
else { write-host 'ok' }
}

Powershell scripting for url custom monitoring

I am trying to build a custom script for URL monitoring. I am able to run the URL's from the file and enter the same in a logfile(named with time stamp).
Till here I have completed
Issue is when I compare the values from present(present timestamp) and previous logfile(previous timestamp).
This portion is not working fine. Please help me correct it.
Here is my code trying to compare value line by line from present logfile and previous logfile and run commands to generate output:
# New log is new logfile data
$Newlog = Get-Content $URLlogfile
$old_file = Dir C:\Scripts\logs | Sort CreationTime -Descending | Select Name -last 1
# Old log is Old logfile data
$oldlog = Get-Content $old_file -ErrorAction SilentlyContinue
Foreach($logdata in $Newlog) {
$url = ($logdata.Split(" "))[0]
$nodename = ($logdata.Split(" "))[1]
$statuscheck = ($logdata.Split(" "))[2]
$description = ($logdata.Split(" "))[3]
$statuscode = ($logdata.Split(" "))[4]
Foreach($log1data in $oldlog) {
$url1 = ($log1data.Split(" "))[0]
$nodename1 = ($log1data.Split(" "))[1]
$statuscheck1 = ($log1data.Split(" "))[2]
$description1 = ($log1data.Split(" "))[3]
$statuscode1 = ($log1data.Split(" "))[4]
While ($url = $url1) {
if ($statuscheck = $statuscheck1 ) {
write-output "output is same"
} elseif ($statuscheck = Fail) {
While ($statuscheck1 = Pass) {
write-output "$url is down at $nodename1- testing event sent"
}
} elseif ($statuscheck = Pass) {
While ($statuscheck1 = Fail) {
write-output "$url is up at $nodename1- testing event sent"
}
}
}
Break
}
}
#At end am clearing the old logs except present one
dir C:\Scripts\logs -recurse | where { ((get-date)-$_.creationTime).minutes -gt 3 } | remove-item -force
Per the comment from BenH, the following part of your code needs correcting as follows:
If ($url -eq $url1) {
if ($statuscheck -eq $statuscheck1 ) {
write-output "output is same"
} elseif ($statuscheck -eq 'Fail' -and $statuscheck1 -eq 'Pass') {
write-output "$url is down at $nodename1- testing event sent"
} elseif ($statuscheck -eq 'Pass' -and $statuscheck1 -eq 'Fail') {
write-output "$url is up at $nodename1- testing event sent"
}
}
Corrections:
In your comparison statements the = needs to be -eq. In PowerShell = always assigns a value.
In your comparison statements Pass and Fail need to be surrounded by single quotes so they are treated as strings (otherwise they are treated like function statements, for functions which don't exist).
I've replaced the While statements with If statements. I'm not sure what the intent of those was but I think they'd just get stuck in an infinite loop as the variable they test is never changed from within the loop.