How do I put a boolean result into a variable in Powershell? - powershell

If I've got a variable $count with a number in it, is there a one-liner to set a variable to either true or false depending on whether $count = 1?
I thought that
$result = ($count -eq 1)
would do it, but I end up with a value of "1" or null stored in it (depending on whether it's 1 or not).
Any idea what I'm doing wrong?
EDIT: My Mistake - I didn't actually have "1" in that variable. I had an ArrayList that looked like it was the number 1. Closing this.
Full code:
get-acl C:\Windows\System32\drivers\etc | select -expand access | where {$_.IdentityReference -eq "SomeACL"} | measure | select -expand count -OutVariable aclCount
$aclFound = ($aclCount –eq 1)
$TodayDate = Get-Date -Format "dd/MM/yyyy hh:mm:ss"
Add-Content f:\myfile.log "$TodayDate $aclFound "
Fixed it by putting a [0] after the $aclCount on line 2.
(Obviously the ACL in there was the one I was checking for)

You can always use an If/Then/Else to do it.
If($Count -eq 1){$result = $true}else{$result = $false}

Can't reproduce.
PS C:\> $count = 3
PS C:\> $result = ($count -eq 1)
PS C:\> $result
False
PS C:\> $result.GetType().Name
Boolean

Related

Exporting PowerShell Results In To CSV for Each User In The Domain That Last Changed Their Password

I have a Powershell script that queries for the pwdLastSet attribute for every user in
the Active Directory domain. Essentially, the script determines when each user in the domain last changed their password. However, when I try and output the result using scriptname.ps1 | Export-Csv "filename.csv" it creates the file, however, I'm not getting the results I see in the console. I'm getting the following:
When I run the script without Export-Csv the results I desire display correctly.
This is the Powershell script:
Trap {"Error: $_"; Break;}
$D = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$Domain = [ADSI]"LDAP://$D"
$Searcher = New-Object System.DirectoryServices.DirectorySearcher
$Searcher.PageSize = 200
$Searcher.SearchScope = "subtree"
$Searcher.Filter = "(&(objectCategory=person)(objectClass=user))"
$Searcher.PropertiesToLoad.Add("distinguishedName") > $Null
$Searcher.PropertiesToLoad.Add("pwdLastSet") > $Null
$Searcher.PropertiesToLoad.Add("userAccountControl") > $Null
$Searcher.SearchRoot = "LDAP://" + $Domain.distinguishedName
$Results = $Searcher.FindAll()
ForEach ($Result In $Results)
{
$DN = $Result.Properties.Item("distinguishedName")
$PLS = $Result.Properties.Item("pwdLastSet")
$UAC = $Result.Properties.Item("userAccountControl")
# Retrieve user password settings to check if password can expire.
$blnPwdExpires = -not (($UAC.Item(0) -band 64) -or ($UAC.Item(0) -band 65536))
If ($PLS.Count -eq 0)
{
$Date = [DateTime]0
}
Else
{
# Interpret 64-bit integer as a date.
$Date = [DateTime]$PLS.Item(0)
}
If ($Date -eq 0)
{
# 0 really means never.
$PwdLastSet = "<Never>"
}
Else
{
# Convert from .NET ticks to Active Directory Integer8 ticks.
# Also, convert from UTC to local time.
$PwdLastSet = $Date.AddYears(1600).ToLocalTime()
}
"$DN;$blnPwdExpires;$PwdLastSet"
}
There are two possible issues on your code, the first one, Export-Csv is expecting an object or object[] as input and will convert it to CSV format, you're already passing a formatted semi-colon delimited string[].
In this case you should use | Out-File path\to\csv.csv instead of Export-Csv.
Do not format objects before sending them to the Export-CSV cmdlet. If Export-CSV receives formatted objects the CSV file contains the format properties rather than the object properties.
An example of what you're passing to the cmdlet and what it actually expects:
PS \> 0..5 | ForEach-Object{ 'asd;asd;asd' } | ConvertTo-Csv
#TYPE System.String
"Length"
"12"
"12"
"12"
"12"
"12"
"12"
PS \> 0..5 | ForEach-Object{ [pscustomobject]#{col1='asd';col2='asd';col3='asd'} } | ConvertTo-Csv -Delimiter ';'
#TYPE System.Management.Automation.PSCustomObject
"col1";"col2";"col3"
"asd";"asd";"asd"
"asd";"asd";"asd"
"asd";"asd";"asd"
"asd";"asd";"asd"
"asd";"asd";"asd"
"asd";"asd";"asd"
The alternative to this, and cleaner approach in my opinion, would be to cast a [pscustomobject]on each iteration of your loop and then pass the resulting array to Export-Csv (code below).
The other possible issue, assuming you're choosing the path of using [pscustomobject], could be that $Result.Properties.Item(...) will yield an object of the type System.DirectoryServices.ResultPropertyValueCollection and you would need to convert it to [string] before passing the results to Export-Csv (also code below).
# Save the resulting pscustomobject array to the $output variable
$output = ForEach ($Result In $Results)
{
...
...
...
# All code should be as is up until:
# "$DN;$blnPwdExpires;$PwdLastSet" => Remove this line
[pscustomobject]#{
DistinguishedName = [string]$DN
blnPwdExpires = [string]$blnPwdExpires
pwdLastSet = [string]$PwdLastSet
}
}
# Then pipe the result to Export-Csv
$output | Export-Csv path\to\csv.csv -NoTypeInformation -Delimiter ';'

Parsing multiple valus in multiple variables

I am trying to find a way to execute a command in powershell and put each line of the result in a different variable to use them later in my script. For example if i execute the below command:
C:\> Get-VMHost -Name hq-esxi-prod-01a.nsx.gss | Get-VM | select Name
I will get the below:
Name
----
HQ-LinServ-01a
HQ-Win2012-01a
HQ-Web-02a
I want to have a script that will add each line in a different variable in a script (excluding the first which is name).
how can i do that.
Thank you for your help.
You can use Set-Variable in a loop to put each value in a separate variable:
$i = 0
... | Get-Vm | Select-Objet -Expand Name | ForEach-Object {
Set-Variable -Name "vm$i" -Value $_
$i++
}
However, that usually isn't good advice. It's more common to put all names in one (array) variable:
$vmList = ...| Get-Vm | Select-Object -Expand Name
so you can access individual names via $vmList[<index>], or (if you need access by some kind of name) in a hashtable:
$i = 0
$vmList = #{}
... | Get-Vm | Select-Objet -Expand Name | ForEach-Object {
$vmList["vm$i"] = $_
$i++
}
Best practice would depend on the particular scenario you need this for, though.
Thank you for your reply,
I have tried you answer but it seems that i am using PowerCLI for VMware it does not include Select-Object -Expand (not sure i had an exception), However your answer have mad me reach to a suitable answer for this.
I have used the below and it worked fine using foreach and adding the values in an array and then reading them as below:
$p1vmname = Get-VMHost -Name hq-esxi-prod-01a.nsx.gss | Get-VM | select Name
$p1vmlist = #()
foreach ($p1line in $p1vmname)
{
$p1vmlist += $p1line
}
$p1 = 0
do {
$x = $p1+1
Write-Host -BackgroundColor:Black -ForegroundColor:Yellow "vm number $x is "$p1vmlist[$p1]"."
$p1++
}
until ($p1 -eq $p1vmc)
}
However when using this the names was not totally correct as they had some additional characters as below:
vm number 1 is #{Name=HQ-Web-01a}
vm number 2 is #{Name=HQ-LinServ-01a}
vm number 3 is #{Name=HQ-Win2012-01a}
so i used split and trim to get rid of these as below and worked fine.
$p1vmname = Get-VMHost -Name hq-esxi-prod-01a.nsx.gss | Get-VM | select Name
$p1vmlist = #()
foreach ($p1line in $p1vmname)
{
$p1vmlist += $p1line
}
$p1 = 0
do {
$x = $p1+1
$p1vmlist[$p1] = ($p1vmlist[$p1]) -split("=") | Select-Object -Last 1
$p1vmlist[$p1] = $p1vmlist[$p1].trimend("}")
Write-Host -BackgroundColor:Black -ForegroundColor:Yellow "vm number $x is "$p1vmlist[$p1]"."
$p1++
}
until ($p1 -eq $p1vmc)
}
Output:
vm number 1 is HQ-Web-01a .
vm number 2 is HQ-LinServ-01a .
vm number 3 is HQ-Win2012-01a .
Thank you so much for your answer that helped me a lot.
I am really enjoying scripting now.

Compare-object output in variable

I'm building a script that will compare the last octed of in-use IPv4 addreses, with all the available octeds (2 till 254).
I am already this far that I do get a result by comparing array's, but my end-result is also an array, and I cannot seem to get only the number.
My script:
$guestIP = #("192.168.31.200","192.168.31.31","192.168.31.90","192.168.31.25","192.168.31.100")
$AllLastOcted = $("2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31","32","33","34","35","36","37","38","39","40","41","42","43","44","45","46","47","48","49","50","51","52","53","54","55","56","57","58","59","60","61","62","63","64","65","66","67","68","69","70","71","72","73","74","75","76","77","78","79","80","81","82","83","84","85","86","87","88","89","90","91","92","93","94","95","96","97","98","99","100","101","102","103","104","105","106","107","108","109","110","111","112","113","114","115","116","117","118","119","120","121","122","123","124","125","126","127","128","129","130","131","132","133","134","135","136","137","138","139","140","141","142","143","144","145","146","147","148","149","150","151","152","153","154","155","156","157","158","159","160","161","162","163","164","165","166","167","168","169","170","171","172","173","174","175","176","177","178","179","180","181","182","183","184","185","186","187","188","189","190","191","192","193","194","195","196","197","198","199","200","201","202","203","204","205","206","207","208","209","210","211","212","213","214","215","216","217","218","219","220","221","222","223","224","225","226","227","228","229","230","231","232","233","234","235","236","237","238","239","240","241","242","243","244","245","246","247","248","249","250","251","252","253","254")
$guestIP = $guestIP | sort -Property {$_-replace '[\d]'},{$_-replace '[a-zA-Z\p{P}]'-as [int]}
$AllLastOcted = $AllLastOcted | sort -Property {$_-replace '[\d]'},{$_-replace '[a-zA-Z\p{P}]'-as [int]}
$guestIP = $guestIP -replace('192.168.31.','')
Compare-Object -ReferenceObject ($AllLastOcted ) -DifferenceObject ($guestIP) | select -Property InputObject -First 1 | set-Variable AvailableOcted -PassThru
$AvailableOcted
My goal is, is that I have as result the first-available octed that I can use.
like:
write-host "IP that can be used is 192.168.31.$AvailableOcted"
PS > IP that can used is 192.168.31.2
You can simplify this a lot.
Instead of defining all numbers from 2 to 254 you can use the range operator to create the array. You also don't need the [int] casts. Instead of using the Compare-Object cmdlet to filter the octeds, you can use the Where-Object cmdlet:
$guestIP = #("192.168.31.200","192.168.31.31","192.168.31.90","192.168.31.25","192.168.31.100")
$AllLastOcted = 2 .. 254
$usedOcted = $guestIP -replace '.*\.'
$nextAvailableOcted = $AllLastOcted | Where { $_ -NotIn $usedOcted } | select -first 1
write-host "IP that can be used is 192.168.31.$nextAvailableOcted"
Output:
IP that can be used is 192.168.31.2
Well, as simple as:
$AvailableOcted.InputObject
would return only the value.
So it would look like this:
write-host ("IP that can be used is 192.168.31." + $AvailableOcted.InputObject)

Conditional Logic and Casting in Powershell

I'm creating a script that imports 2 columns of CSV data, sorts by one column cast as type int, and shows only the values between 0 and 10,000. I've been able to get up to the sorting part, and I am able to show only greater than 0. When I try to add "-and -lt 10000" various ways, I am unable to get any useful data. One attempt gave me the data as if it were string again, though.
This only gives me > 0 but sorts as type int. Half way there!:
PS C:\> $_ = Import-Csv .\vc2.csv | Select -Property User_Name, Minutes; $_ | Sort {[int] $_.Minutes} | Where {($_.Minutes -gt 0)}
This gives me 10000 > x > 0 but sorts as string:
PS C:\> $_ = Import-Csv .\vc.csv | Select -Property User_Name, Minutes; $_ | Sort {[int] $_.Minutes} | Where {($_.Minutes -gt 0) -and ($_.Minutes -lt 10)}
Here and here are where I tried recasting as int and it gave me many errors:
PS C:\> $_ = Import-Csv .\vc.csv | Select -Property User_Name, Minutes; $_ | Sort {[int] $_.Minutes} | Where {[int]{($_.Minutes -gt 0) -and ($_.Minutes -lt 10000)}}
PS C:\> $_ = Import-Csv .\vc.csv | Select -Property User_Name, Minutes; $_ | Sort {[int] $_.Minutes} | Where { ({[int]$_.Minutes} -gt 0) -and ({[int]$_.Minutes} -lt 10000) }
Error: Cannot convert the "($.Minutes -gt 0) -and ($.Minutes -lt 10000)" value of type "System.Management.Automation.ScriptBlock" to type "System.Int32".
What is the proper syntax for this?
PowerShell usually coerces arguments of binary operators to the type of the left operand. This means when doing $_.Minutes -gt 10 the 10 gets converted to a string, because the fields in a parsed CSV are always strings. You can either switch the operands around: 10 -lt $_.Minutes or add a cast: [int]$_.Minutes -gt 10 or +$_.Minutes -gt 10.
Usually, when dealing with CSVs that contain non-string data that I want to use as such, I tend to just add a post-processing step, e.g.:
Import-Csv ... | ForEach-Object {
$_.Minutes = [int]$_.Minutes
$_.Date = [datetime]$_.Date
...
}
Afterwards the data is much nicer to handle, without excessive casts and conversions.
The problem is the use of the { and } brackets in the Where statement. Those are being interpreted as script blocks.
Where { ({[int]$_.Minutes} -gt 0) -and ({[int]$_.Minutes} -lt 10000) }
Try using ( and ) or excluding them altogether.
Where { (([int]$_.Minutes) -gt 0) -and (([int]$_.Minutes) -lt 10000) }
The way you're assigning values to $_ is also weird.
$_ represents the current value in the pipeline.
$list = #(1,2,3)
$list | foreach { $_ }
1
2
3
by assigning "$_" a value, you are losing that value as soon as you place it in the pipeline.
try something like:
$mycsv = import-csv .\vc.csv; $mycsv | select ...etc

Iterating over a sorted hashtable with Select-String includes blank lines?

I'm trying to extract certain values from a sorted hash table using Select-String.
This works, but why are there extra blank lines in the output?
cls
$fruits = #{"1" = "apple"; "2" = "lemon"; "3" = "orange"; "4" = "apricot"}
foreach ($fruit in $fruits.GetEnumerator() | Sort-Object Value) {
$fruit.Value | Select-String -pattern "ap" -SimpleMatch
}
I think you're getting the empty values because for each item you're doing a Select-String, which is returning a value sometimes but nothing at other times - those nothings are the blank lines.
Try something like this that uses Where-Object:
$fruits.Values | Sort-Object | Where-Object { $_ -match "ap" }
I'm using PowerShell 3.0.
I did two lines of code
PS C:\> $fruits = #{"1" = "apple"; "2" = "lemon"; "3" = "orange"; "4" = "apricot"}
PS C:\> $fruits.Values -like 'ap*'
apricot
apple
PS C:\>
Further Investigating
Seems to be that when there is no match it returns NULL.
foreach($key in $fruits.Keys){(Select-String -Pattern 'ap' -SimpleMatch -InputObject $fruits[$key]) -eq $NULL}
Since it is not redirecting to a variable it just prints NULL to the Host. That's my assumption (assume).
Strange...good question.