I have a quick powershell syntax question. I have following loop in powershell. I would like to know which value exists (which is easy). I can use either "Read" or "Visitor" to assign permission. I can do 2 if statements but if there is a smarter way i would rather use that.
if(($listRA.Member.Name) -ne $authUsers)
{
foreach($spRoleDefinition in $rc)
{
if(($spRoleDefinition.Name -eq "Read") -OR ($spRoleDefinition.Name -eq "SP Visitor"))
{
Need to determine which one exists
Adding a user code....
write-host $spRoleDefinition.Name
}
}
}
Use a switch statement:
if(($listRA.Member.Name) -ne $authUsers)
{
foreach($spRoleDefinition in $rc)
{
switch($spRoleDefinition.Name)
{
'Read' {
# do Read stuff
break;
}
'SP Visitor' {
# do SP Visitor stuff
break;
}
}
}
}
Related
How do I call methods within workflow?
I am trying to call "Task" from within a workflow and it seems to be getting ignored? I have provided a watered down nonsense code to illustrate what I'm trying to do. basically call a method within the class in parallel and return the results.
Sample Code
Class Something {
[string]Task($item) {
Start-sleep -Seconds 10
Return "Result"
}
[System.Array]GetSomething($list) {
workflow GetWF {
param($listarr)
ForEach -parallel ($item in $listarr) {
$res = InlineScript {
Write-Host("Starting.." + $using:item)
$this.Task($using:item)
}
}
$res
}
Return GetWF -listarr $list
}
}
$list = #('host1','host2','host3','host4')
$Something = [Something]::New()
$Something.GetSomething($list)
Output :
Starting..host1
Starting..host4
Starting..host2
Starting..host3
Desired Result from Example
The issue is how do I get my results back as an array ? In this example above I would like to see the final result to be this:
$Result = #("Result","Result","Result","Result")
I am working on implementing a singleton class to store some regularly accessed status information for my script, including hacking around the issue of $myInvocation only being populated in the main script. All working as planned with this.
class pxStatus {
static [pxStatus] $singleton = $null
[string]$Context = 'machine'
[string]$Path = $null
[datetime]$StartTime = (Get-Date)
pxStatus ([string]$path) {
if ([pxStatus]::singleton -eq $null) {
$this.Path = $path
[pxStatus]::singleton = $this
} else {
Throw "Singleton already initialized"
}
}
static [pxStatus] Get() {
if ([pxStatus]::singleton -eq $null) {
Throw "Singleton not yet initialized"
} else {
return [pxStatus]::singleton
}
}
}
CLS
[void]([pxStatus]::New((Split-Path ($myInvocation.myCommand.path) -parent)))
([pxStatus]::Get()).StartTime
([pxStatus]::Get()).Context
([pxStatus]::Get()).Path
With one exception. Even with that [void] on the [pxStatus]::New() line, I am getting a blank line in the console. Even $null = ([pxStatus]::New((Split-Path ($myInvocation.myCommand.path) -parent))) is echoing a blank line to the console. And for the life of me I can't see what is causing it.
It's not new that causes a blank line but ([pxStatus]::Get()).StartTime.
To fix the issue, you may output it as string, i.e. not formatted, e.g. ([pxStatus]::Get()).StartTime.ToString()
You problem has already been diagnosed, but I wanted to take a second to show how to actually implement a singleton-like type in PowerShell (see inline comments):
class pxStatus {
# hide backing field from user
hidden static [pxStatus] $singleton = $null
[string]$Context = 'machine'
[string]$Path = $null
[datetime]$StartTime = (Get-Date)
# hide instance constructor, no one should call this directly
hidden pxStatus ([string]$path) {
# Only allow to run if singleton instance doesn't exist already
if ($null -eq [pxStatus]::singleton) {
$this.Path = $path
} else {
Throw "Singleton already initialized - use [pxStatus]::Get()"
}
}
# Use a static constructor to initialize singleton
# guaranteed to only run once, before [pxStatus]::Get() or [pxStatus]::singleton
static pxStatus () {
# grab the path from context, don't rely on user input
if(-not $PSScriptRoot){
throw "[pxStatus] can only be used in scripts!"
}
# this will only succeed once anyway
[pxStatus]::singleton = [pxStatus]::new($PSScriptRoot)
}
static [pxStatus] Get() {
# No need to (double-)check ::singleton, static ctor will have run already
return [pxStatus]::singleton
}
}
[pxStatus]::Get().StartTime
Pardon me if this question has already been answered on this site. I haven't been able to find it through my research thus far.
Question:
As I step through each row of formatted table , I'm trying to determine if a column (CompletionDate) is missing it's value
Below is an example table:
DueDate, StartDate, CompletionDate
2017-06-10T22:00:29.08, 2017-05-30T20:38:37.913, 2017-05-30T20:44:05.517
2017-06-09T16:00:21.38, 2017-06-07T15:55:14.627,
Below is some of my code thus far:
foreach ($row in $tableData) {
if ($row.CompletionDate -eq ''){
write-host 'no value'
}
else {
Write-Host 'has value'
}
}
Thanks in advance for your help. If this question has been answered before, please just let me know where it is, and I'll take this question down.
}
You can use the IsNullOrEmpty method:
foreach ($row in $tableData) {
if ([string]::IsNullOrEmpty($row.CompletionDate)){
write-host 'no value'
}
else {
Write-Host 'has value'
}
}
try this
foreach ($row in $tableData)
{
if ($row.CompletionDate)
{
'has value'
}
else
{
'no value'
}
}
I am trying to parse values from an XML file that will add items to a collection using a foreach loop, then add the items from that collection to another collection using another foreach loop with an addition value. This is what I am doing so far:
[xml]$testResults = Get-Content -Path $testResultsPath
$resultsByName = #{}
$resultsByPhone = #{}
$loop = 0
foreach($testCase in $testResults.'test-results'.'test-suite')
{
foreach($testCase in $testResults.'test-results'.'test-suite'[$loop].'results'.'test-suite'.'results'.'test-suite'.'results'.
'test-suite'.'results'.'test-suite'.'results'.'test-suite'.'results'.'test-suite'.'results'.'test-case')
{
$NameWithPone = $testCase.name.ToUpper().Substring($testCase.name.LastIndexOf('.')+1);
$Name =$NameWithPone.Substring(0, $NameWithPone.IndexOf('_'));
$PhoneVersion = $testCase.name.Substring($testCase.name.IndexOf('_')+1);
$resultsByName.Add($PhoneVersion, $Name)
Foreach($resultCase in $resultsByName)
{
$resultsByPhone.Add($resultsByName, $testCase.result)
}
}
$loop++
}
But this will only add it first result, then give the error "Item has already been added. Key in dictionary:
'System.Collections.Hashtable' Key being added: 'System.Collections.Hashtable'" I think this is because I am adding the same item each time, how can I correct this?
The first collection will look like this:
google_pixel_xl-7_1_1 TESTTHATAREGISTEREDUSERCANLOGINTOTHECUSTOMERAPPSUCCESSFULLY
htc_10-6_0_1 TESTTHATAREGISTEREDUSERCANLOGINTOTHECUSTOMERAPPSUCCESSFULLY
oneplus_one-4_4_4 TESTTHATAREGISTEREDUSERCANLOGINTOTHECUSTOMERAPPSUCCESSFULLY
But I want to add both values together to another collection which would look like:
google_pixel_xl-7_1_1 TESTTHATAREGISTEREDUSERCANLOGINTOTHECUSTOMERAPPSUCCESSFULLY Error
I got this done by doing this:
[xml]$testResults = Get-Content -Path $testResultsPath
foreach($testCase in $testResults.'test-results'.'test-suite')
{
function Get-TestCases($myResults)
{
$testCases = #()
foreach($child in $myResults.ChildNodes)
{
if($child.'test-case' -eq $null)
{
foreach($testCase in Get-TestCases $child)
{
$testCases += $testCase
}
}
else
{
$testCases += $child.'test-case'
}
}
return $testCases
}
$tests = Get-TestCases $testResults.'test-results'.'test-suite'[$loop]
foreach($test in $tests)
{
$PhoneVersion = $test.name.Substring($test.name.IndexOf('_')+1);
$resultsByPhone.Add($PhoneVersion, #{})
$NameWithPhone = $test.name.ToUpper().Substring($test.name.LastIndexOf('.')+1);
$Name =$NameWithPhone.Substring(0, $NameWithPhone.IndexOf('_'));
$resultsByPhone[$phoneVersion].Add($Name, $test.result)
}
$resultsByPhone[$phoneVersion]
$resultsByPhone
$loop++
}
I have read in different sources that the SWITCH statement yields better performance than multiple IF statements. I have the following blocks of IF statements which have parallel conditions. Is it possible to do this in a SWITCH block?
if (($statusCode -eq "OK:") -and ($messageOutput)) {
$returnValue = 0
return $returnValue
}
if (($statusCode -eq "WARNING:") -and ($messageOutput)) {
$returnValue = 1
return $returnValue
}
Thanks in advance,
You have a constant here which is $messageOutput, so the conditions aren't really parallel. You could do:
if($messageOutput) {
switch ($statusCode) {
"OK:" { 0 }
"WARNING:" { 1 }
default { 1 }
}
}
This would be more efficient as you don't need to recheck each variable for each condition.
Arco444 has the best answer for this particular case. However it is worth noting that it is possible to have multiple conditions in a switch block. In case another SO user finds their way here:
Switch($true){
(($statusCode -eq "OK:") -and ($messageOutput)){"Alright"}
(($statusCode -eq "WARNING:") -and ($messageOutput)){"Not Alright"}
default{"Something Wrong"}
}
The conditions are all evalutaed based on if the are $true. The default would catch if none of the other conditions are true.
Here's one way to approach multiple conditions with a Switch:
Switch ([string][int[]]($Condition1,$Condition2))
{
'1 1' { 'Both conditions are true' }
'1 0' { 'Condition1 is true and Condition2 is false' }
'0 1' { 'Condition1 is false and Condition2 is true' }
'0 0' { 'Both conditions are false' }
}