Using a switch statement instead of multiple IF's - powershell

Hi I have the below code and wanted to know the best way to replace it using a switch statement.This example I have 4 possible outcomes but I might end up with over 20 and if statements would get to cluttered .
$Des = "C:\tools\"
$DListFiles = Get-ChildItem $Des -EA 0
IF((Test-Path $Des)-ne $false -and $DListFiles -eq $null){$DDE = 1}
ElseIF((Test-Path $Des)-ne $false -and $DListFiles -ne $null){$DDE = 2}
ElseIF((Test-Path $Des)-eq $false){$DDE = 3}
Else{$DDE = 4}
write-host "$DDE"

For the example that you posted, personally I would use a nested if to make the logic clearer:
If(Test-Path $Des){
If($DListFiles -eq $null){
$DDE = 1
}Else{
$DDE = 2
}
}Else{
If($DListFiles -eq $null){
$DDE = 3
}else{
$DDE = 4
}
}
By the way, the way that you have it written does not give the logic that I think that you want. I don't believe you would ever get $DDE = 2. If I'm reading what you posted correctly, the logic table is posted below. Again, a Nested If would help sort it out.
Test-Path $Dlist is Null $DDE
TRUE TRUE 1
FALSE FALSE 3
TRUE TRUE 4
FALSE FALSE 3

I ended up figuring some thing out that would work let me know what you all think.
$Des = "c:\test\"
$DListFiles = Get-ChildItem $Des -EA 0
Switch($Des)
{ {!$Des} {$DDE = 4; break}
{((Test-Path $Des)-ne $false -and $DListFiles -eq $null)} {$DDE = 1; break}
{((Test-Path $Des)-ne $false -and $DListFiles -ne $null)} {$DDE = 2; break}
{((Test-Path $Des)-eq $false)} {$DDE = 3; break}
}
$DDE

Related

Problem assign data from a file read to variables

This is a PowerShell question, sorry if it wound up in the wrong place.
I have a data file which I will call PS_Upgrade_Data. It has 6 items in it listed like this:
item1=item-2=item.3=item 4=item5=item6
Please note that items 2 through 4 are written that way due to the data coming in over which I have no control. There is a dash in item2, a period in intem3 and a space in item4 just to be clear. Items 1, 5, and 6 have nothing between the word item and the number.
I am using the follow PS line to read the data in from the file:
Get-Content "P:\PS_Upgrade_Data.txt" | Where-Object {$_.length -gt 0} | Where-Object {!$_.StartsWith("#")} | Foreach-Object -begin {$count1=0} -process {$var = $_.Split('=',6).Trim()}
This does read the data from the file in ok.
I want to take that data and drop it into six (6) different variables and I tried a foreach loop like the one below:
$count1 = 0
ForEach ($item in $var) {
Write-Host "`n"
Write-Host "count = " , $count1
if($count1 = 0) {
Write-Host "UserInit"
$UserInit = $item
}
elseif ($count1 = 1) {
Write-Host "UserInit"
$TicketNumber = $item
}
elseif ($count1 = 2) {
Write-Host "UserInit"
$UpgradeVersion = $item
}
elseif ($count1 = 3) {
Write-Host "UserInit"
$ClientName = $item
}
elseif ($count1 = 4) {
Write-Host "UserInit"
$InstName = $item
}
elseif ($count1 = 5) {
Write-Host "UserInit"
$Coffee = $item
}
$count1 +=1
}
The problem is that the counter is jumping from 0 (zero) to two (2) and then wont increase and I have no idea why.
What stupid thing am I doing or missing?
Thanks for any help.
PowerShell's assignment operator = supports multiple assignment targets per operation, so you can skip the counter and foreach loop and instead, simply do:
Get-Content "P:\PS_Upgrade_Data.txt" | Where-Object {$_.length -gt 0} | Where-Object {!$_.StartsWith("#")} | Foreach-Object {
$UserInit,$TicketNumber,$UpgradeVersion,$ClientName,$InstName,$Coffee = $_.Split('=',6).Trim()
# do with your variables what you want here
}

Powershell - Exchange JSON output without needing to write to a file

EDIT: Added Setupconfigfiles.ps1
I'm a bit new to detailed scripting so please bear with me.
I have two Powershell scripts
Setupconfigfiles.ps1 generates JSON output to be fed to an API.
Script2 uses that JSON data to execute API commands.
Script 2 can call setupconfigfiles.ps1 as indicated below and use the output data.
.\SetupConfigFiles.ps1 -type $Type -outfile .\Templist.json
$servers = Get-Content -Raw -Path .\templist.json | ConvertFrom-Json
setupconfigfiles.ps1:
param (
# If this parameter is set, format the output as csv.
# If this parameter is not set, just return the output so that the calling program can use the info
[string]$outfile,
# this parameter can be 'production', 'development' or 'all'
[string]$type
)
enum MachineTypes {
production = 1
development = 2
all = 3
}
$Servers = Get-ADObject -Filter 'ObjectClass -eq "computer"' -SearchBase 'Obfuscated DSN' | Select-Object Name
$output = #()
$count = 0
# Set this to [MachineTypes]::production or [MachineTypes]::development or [MachineTypes]::all
if ($type -eq "all") {
$server_types = [MachineTypes]::all
}
ElseIf ($type -eq "production") {
$server_types = [MachineTypes]::production
}
else {
$server_types = [MachineTypes]::development
}
ForEach ($Server in $Servers)
{
$count = $count + 1
$this_server = #{}
$this_server.hostname = $Server.Name
$this_server.id = $count
$this_server."site code" = $this_server.hostname.substring(1,3)
$this_server."location code" = $this_server.hostname.substring(4,2)
if ($this_server.hostname.substring(7,1) -eq "P") {
$this_server.environment = "Production"
}
ElseIf ($this_server.hostname.substring(7,1) -eq "D") {
$this_server.environment = "Development"
}
Else {
$this_server.environment = "Unknown"
}
if (($server_types -eq [MachineTypes]::production ) -and ($this_server.environment -eq "Production")) {
$output += $this_server
}
ElseIf (($server_types -eq [MachineTypes]::development ) -and ($this_server.environment -eq "Development")) {
$output += $this_server
}
Else {
if ($server_types -eq [MachineTypes]::all ) {
$output += $this_server
}
}
}
if ($outfile -eq "")
{
ConvertTo-Json $output
}
else {
ConvertTo-Json $output | Out-File $outfile
}
How can I do it without needing to write to the Templist.json file?
I've called this many different ways. The one I thought would work is .\SetupConfigFiles.ps1 $servers
Y'all are great. #Zett42 pointed me in a direction and #Mathias rounded it out.
The solution was to change:
"ConvertTo-Json $output" to "Write-Output $output"
Then it's handled in the calling script.
thanks!

Powershell Return only TRUE if All Values are the same

I have the script below to read registry values from a certain key(taking no credit for it). My end goal is to only return TRUE if all the values in the array Match. However I'm not quite getting it as
Example Registry Entry
$array = #()
$regval = Get-Item -Path HKLM:\SOFTWARE\Runner\Event
$regval.GetValueNames() |
ForEach-Object {
$name = $_
$rv.Value
$array += New-Object psobject -Property #{'Value' = $rv.Value }
}
$Matchvalue = 'A'
Foreach ($v in $array){
if ($v -match $Matchvalue){
$true
}
}
Update: I've just tried again and it appears my array is empty. So any tips welcome for me.
How about this:
$regkey = Get-Item HKLM:\SOFTWARE\Runner\Event
$matchPattern = 'A'
$values = $regkey.GetValueNames()
$matchingValues = $values | Where { $regkey.GetValue($_) -match $matchPattern }
# this is going to be true or false
$values.Count -eq $matchingValues.Count
Note that by default, Powershell is case-insensitive. So $matchPattern = 'A' and $matchPattern = 'a' will behave the same.
Here's my attempt to do something like Haskell's "all".
function foldr ($sb, $accum, $list) {
if ($list.count -eq 0) { $accum }
else { & $sb $list[0] (foldr $sb $accum $list[1..$list.length]) }
}
function and ($list) {
foldr { $args[0] -and $args[1] } $true $list
}
function all ($list, $sb) {
and ( $list | foreach $sb )
}
all 1,1,1 { $_ -eq 1 }
True
all 1,2,1 { $_ -eq 1 }
False

How to fix 'The Decimals'

I am pulling the info from a SharePoint list. Everything is ok, but the results from the list prints as 2018.0000000 for the year column and the results from current_high and current_medium prints as 4.0000000, 26.0000000 respectively. I have tried all the functions float, decimal, round everything. But I couldn't round of the 0's. Can anyone help me on this one?
Select-Object ows_Year, ows_Status, ows_App, ows_cycle, ows_Current_Critical,
ows_Current_High, ows_Current_Medium, #{Name='Result'; Expression={
ForEach-Object {
$d1 = (Get-Date).ToString("MM-dd")
$d2 = (Get-Date 2018-12-28).ToString("MM-dd")
if ($d1 -eq $d2) {
if ($_.ows_Cycle -eq 'Cycle 1') {
if ([int]($_.ows_Current_Critical) -eq 0 -and [int]($_.ows_Current_High) -eq 0 -and [int]($_.ows_Current_Medium) -eq 0) {
'Pass'
} else {
'Fail'
}
}
}
}
}} |
Even though guys in comments already pointed out how to perform such task it still might be a little confusing. So all together:
Select-Object #{Name='ows_Year'; Expression={[Int]$_.ows_Year}}, ows_Status, ows_App, ows_cycle, ows_Current_Critical,
ows_Current_High, ows_Current_Medium, #{Name='Result'; Expression={
ForEach-Object {
$d1 = (Get-Date).ToString("MM-dd")
$d2 = (Get-Date 2018-12-28).ToString("MM-dd")
if ($d1 -eq $d2) {
if ($_.ows_Cycle -eq 'Cycle 1') {
if ([int]($_.ows_Current_Critical) -eq 0 -and [int]($_.ows_Current_High) -eq 0 -and [int]($_.ows_Current_Medium) -eq 0) {
'Pass'
} else {
'Fail'
}
}
}
}
}} |

PowerShell Is there a way to get proper order of properties in Select-Object so that each object has order?

Following code lists all AD users.
$Domain.DomainUsersFullList = Get-ADUser -Server $Domain -ResultPageSize 500000 -Filter * -Properties *, "msDS-UserPasswordExpiryTimeComputed" | Select * -ExcludeProperty *Certificate, PropertyNames, *Properties, PropertyCount, Certificates
$($Domain.DomainUsersFullList[0]).PSObject.Properties.Name[12]
$($Domain.DomainUsersFullList[10]).PSObject.Properties.Name[12]
It seems that order returned by PSObject.Properties.Name can be different. Is there a way to order properties without exclusively telling Select-Object the order you want them in?
Just for the sake of why I need this:
https://github.com/EvotecIT/PSWriteWord - I wrote a function Add-WordTable that takes any $Object and puts this into Word document. No need to parse objects yourself. Just pass it to function and it will be put into Word document.
I am now working on same thing for:
https://github.com/EvotecIT/PSWriteExcel - which has function Add-ExcelWorksheetData that does exactly the same as above with one exception .. since it's Excel you don't have column limit. So with 100 columns I was/am getting wrong order per each row. Which makes no sense.
While in case of WORD document I didn't notice this issue because I never added more then 10 columns, with Excel and 100 columns I was getting wrong order. Below is an example of this:
Here is the method that does the conversion:
function Format-PSTableConvertType2 {
[CmdletBinding()]
param(
$Object,
[switch] $SkipTitles,
[string[]] $ExcludeProperty,
[switch] $NoAliasOrScriptProperties,
[switch] $DisplayPropertySet
)
[int] $Run = 0
$Array = New-ArrayList
$Titles = New-ArrayList
if ($NoAliasOrScriptProperties) {$PropertyType = 'AliasProperty', 'ScriptProperty' } else {$PropertyType = ''}
Write-Verbose "Format-PSTableConvertType2 - Option 2 - NoAliasOrScriptProperties: $NoAliasOrScriptProperties"
foreach ($O in $Object) {
$ArrayValues = New-ArrayList
if ($DisplayPropertySet -and $O.psStandardmembers.DefaultDisplayPropertySet.ReferencedPropertyNames) {
$ObjectProperties = $O.psStandardmembers.DefaultDisplayPropertySet.ReferencedPropertyNames.Where( { $ExcludeProperty -notcontains $_ } ) #.Name
} else {
$ObjectProperties = $O.PSObject.Properties.Where( { $PropertyType -notcontains $_.MemberType -and $ExcludeProperty -notcontains $_.Name } ).Name
}
#$ObjectProperties = $O.PSObject.Properties
foreach ($Name in $ObjectProperties) {
if ($Run -eq 0 -and -not $SkipTitle) { Add-ToArray -List $Titles -Element $Name }
Add-ToArray -List $ArrayValues -Element $O.$Name
}
if ($Run -eq 0 -and -not $SkipTitle) {Add-ToArray -List ($Array) -Element $Titles }
Add-ToArray -List $Array -Element $ArrayValues
$Run++
}
return , $Array
}
It essentially converts object into Array of Arrays. Which then makes it trivial to just loop thru rows / columns.
Now it's important that while generally I could probably make Get-AdUser display only values I want in proper order I am working on general use modules (PSWriteWord/PSWriteExcel) and I want people to pass any object to it and not have to care about it too much.
Unless anyone has a better option:
$SpecialData = $Domain.DomainUsersFullList | Select-Object $($Domain.DomainUsersFullList[0]).PSObject.Properties.Name
$($Domain.DomainUsersFullList[0]).PSObject.Properties.Name[12]
$($Domain.DomainUsersFullList[10]).PSObject.Properties.Name[12]
$($SpecialData[0] | Select-Object $($Domain.DomainUsersFullList[0]).PSObject.Properties.Name).PSObject.Properties.Name[12]
$($SpecialData[10] | Select-Object $($Domain.DomainUsersFullList[0]).PSObject.Properties.Name).PSObject.Properties.Name[12]
Basically what this does is copy the order of 1st element and applies same order to each and every new line. This ensures that each object will return properties in same order as 1st element.
Final implementation:
function Format-PSTableConvertType2 {
[CmdletBinding()]
param(
$Object,
[switch] $SkipTitles,
[string[]] $ExcludeProperty,
[switch] $NoAliasOrScriptProperties,
[switch] $DisplayPropertySet,
$OverwriteHeaders
)
#[int] $Run = 0
$Array = New-ArrayList
$Titles = New-ArrayList
if ($NoAliasOrScriptProperties) {$PropertyType = 'AliasProperty', 'ScriptProperty' } else {$PropertyType = ''}
Write-Verbose "Format-PSTableConvertType2 - Option 2 - NoAliasOrScriptProperties: $NoAliasOrScriptProperties"
# Get Titles first (to make sure order is correct for all rows)
if ($OverwriteHeaders) {
$Titles = $OverwriteHeaders
} else {
foreach ($O in $Object) {
if ($DisplayPropertySet -and $O.psStandardmembers.DefaultDisplayPropertySet.ReferencedPropertyNames) {
$ObjectProperties = $O.psStandardmembers.DefaultDisplayPropertySet.ReferencedPropertyNames.Where( { $ExcludeProperty -notcontains $_ } ) #.Name
} else {
$ObjectProperties = $O.PSObject.Properties.Where( { $PropertyType -notcontains $_.MemberType -and $ExcludeProperty -notcontains $_.Name } ).Name
}
foreach ($Name in $ObjectProperties) {
Add-ToArray -List $Titles -Element $Name
}
break
}
# Add Titles to Array (if not -SkipTitles)
if (-not $SkipTitle) {
Add-ToArray -List $Array -Element $Titles
}
}
# Extract data (based on Title)
foreach ($O in $Object) {
$ArrayValues = New-ArrayList
foreach ($Name in $Titles) {
Add-ToArray -List $ArrayValues -Element $O.$Name
}
Add-ToArray -List $Array -Element $ArrayValues
}
return , $Array
}