How to fix 'The Decimals' - powershell

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'
}
}
}
}
}} |

Related

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!

CSV multiple filters

Im importing a csv and have multiple filters that the end user can select to filter the csv.
foreach filter Im += to an array.
Problem I run into is-
If a user selects 'Medium' and USD, they should only be able to see Rows of data which has both 'Medium' from the impact column and USD from country.
My results are returning 'Medium' from any country AND 'USD' events?
I feel like Im going about this the wrong way. Any ideas?
Thank you for your time.
$buttonFilter_Click={
$r = #()
#Filter Impact Column#
if ($checkboxLow.Checked -eq $true)
{
$r += $script:WorldWideNews | ? { $_.Impact -eq 'Low' }
}
if ($checkboxMedium.Checked -eq $true)
{
$r += $script:WorldWideNews | ? { $_.Impact -eq 'Medium' }
}
if ($checkboxHigh.Checked -eq $true)
{
$r += $script:WorldWideNews | ? { $_.Impact -eq 'High' }
}
#Filter Country column#
if ($checkboxUSD.Checked -eq $true)
{
$r += $script:WorldWideNews | ? { $_.Country -eq 'USD' }
}
if ($checkboxCHF.Checked -eq $true)
{
$r += $script:WorldWideNews | ? { $_.Country -eq 'CHF' }
}
if ($checkboxGBP.Checked -eq $true)
{
$r += $script:WorldWideNews | ? { $_.Country -eq 'GBP' }
}
if ($checkboxAUD.Checked -eq $true)
{
$r += $script:WorldWideNews | ? { $_.Country -eq 'AUD' }
}
if ($checkboxCNY.Checked -eq $true)
{
$r += $script:WorldWideNews | ? { $_.Country -eq 'CNY' }
}
if ($checkboxJPY.Checked -eq $true)
{
$r += $script:WorldWideNews | ? { $_.Country -eq 'JPY' }
}
if ($checkboxCAD.Checked -eq $true)
{
$r += $script:WorldWideNews | ? { $_.Country -eq 'CAD' }
}
if ($checkboxEUR.Checked -eq $true)
{
$r += $script:WorldWideNews | ? { $_.Country -eq 'EUR' }
}
if ($checkboxNZD.Checked -eq $true)
{
$r += $script:WorldWideNews | ? { $_.Country -eq 'NZD' }
}
$table = ConvertTo-DataTable -InputObject $r
Update-DataGridView -DataGridView $datagridviewUpcomingNews -Item $table
}
Your code forms the union of all filter results, along both dimensions, impact and country (currency).
Instead, you need the intersection of the results from these two dimensions.
The immediate fix is to collect an intermediate result for the filtering performed along the first dimension, and then base the filtering along the second dimension on that:
$r = #()
#Filter Impact Column#
if ($checkboxLow.Checked)
{
$r += $script:WorldWideNews | ? { $_.Impact -eq 'Low' }
}
# ...
# Save the results of the impact filtering
# and base all subsequent filtering on that.
$impactFilterResults = $r
$r = #()
#Filter Country column# - note the use of $impactFilterResults as input.
if ($checkboxUSD.Checked)
{
$r += $impactFilterResults | ? { $_.Country -eq 'USD' }
}
if ($checkboxCHF.Checked)
{
$r += $impactFilterResults | ? { $_.Country -eq 'CHF' }
}
# ...
Note, however, that your code can be streamlined, by ultimately combining all filters into a composite one that a single Where-Object (?) call could perform:
$buttonFilter_Click = {
# Map the checkboxes to the corresponding values to filter by.
$impactValueMap = #{
$checkboxLow = 'Low'
$checkboxMedium = 'Medium'
$checkboxHigh = 'High'
}
# Based on which are checked, determine the list of values to filter by.
[array] $impactsToFilterBy = foreach ($checkbox in $checkboxLow, $checkboxMedium, $checkboxHigh) {
if ($checkbox.Checked) { $impactValueMap[$checkbox] }
}
# Note: Truncated to 3 entries for brevity
$countryValueMap = #{
$checkboxUSD = 'USD'
$checkboxCHF = 'CHF'
$checkboxGBP = 'GBP'
# ...
}
[array] $countriesToFilterBy = foreach ($checkbox in $checkboxUSD, $checkboxCHF, $checkboxGBP) {
if ($checkbox.Checked) { $countryValueMap[$checkbox] }
}
# Use a single Where-Object call to filter, based
# on *arrays* of values to match.
$r =
$script:WorldWideNews |
Where-Object { $_.Impact -in $impactsToFilterBy -and $_.Country -in $countriesToFilterBy }
$table = ConvertTo-DataTable -InputObject $r
Update-DataGridView -DataGridView $datagridviewUpcomingNews -Item $table
}

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

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
}

Using a switch statement instead of multiple IF's

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