Computername and string search - string

Having some string trouble, I can get the computer name using $env:computerName and it returns something like ABC1211. I am guessing that the ABC1211 is an object and I want to do a search. I want to search this for the characters ABC and then I need to do some other things with certs. I am having problem searching for the ABC.
I tried:
[string[]]$test = $env:computerName
to turn it into a string and then do a search within $test by:
if ($test.contains(("DEF")) {
Write-Host "Yeah"
}
else {
Write-Host "NO"
}
but its not working. Am I missing something? I am guessing this is really simple, but I'm just not getting it.

$env:computerName is already a string. There is no need to cast it to [string[]]. Just call the .contains method on the variable directly:
if ($env:computerName.contains("ABC")) {
Write-Host "Yeah"
}
else {
Write-Host "NO"
}
Incidentally, casting a variable to [string[]] makes an array of strings, not a single string:
PS > [string[]]$test = $env:computerName
PS > $test.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String[] System.Array
PS >
So, $test was actually of the form ($env:computerName,) and you were using Array.Contains instead of String.Contains.
To cast to a string, you would use just [string]:
[string]$test = $env:computerName
But as I said above, this is unnecessary since $env:computerName is already a string.

Ok I figured it out...was a lot more simple than I thought. Here's the answer: -match
I just had to use that instead of .contains or -like also I don't need to change the object into a string.

Related

How to get a hashtable in PowerShell from a multiline string in which keys and values are on different lines?

I have a string of the following format (the number of lines in this string may vary):
$content = #"
key1
value1
key2
value2
key3
value3
"#
I want to put this data in a hashtable.
(In my case, the data in the $content variable is received in the body of the HTTP response from the Invoke-WebRequest cmdlet by Client/Server Protocol in the 'LiveJournal'. But I am interested in the answer to my question for the general case as well.)
I tried to use the cmdlet ConvertFrom-StringData, but it doesn't work for this case:
PS C:\> ConvertFrom-StringData -StringData $content -Delimiter "`n"
ConvertFrom-StringData: Data line 'key1' is not in 'name=value' format.
I wrote the following function:
function toHash($str) {
$arr = $str -split '\r?\n'
$hash = #{}
for ($i = 0; $i -le ($arr.Length - 1); $i += 2) {
$hash[$arr[$i]] = $arr[$i + 1]
}
return $hash
}
This function works well:
PS C:\> toHash($content)
Name Value
---- -----
key3 value3
key2 value2
key1 value1
My question is: is it possible to do the same thing, but shorter or more elegant? Preferably in one-liner (see the definition of this term in the book 'PowerShell 101'). Maybe there is a convenient regular expression for this case?
As commented by #Santiago Squarzon;
The code you already have looks elegant to me, shorter -ne more elegant
For the "Preferably in one-liner", what exactly is definition of a one line:
A single line, meaning a text string with no linefeeds?
Or a single statement meaning a text string with no linefeeds and no semicolons?
Knowing that there are several ways to cheat on this, like assigning a variable in a condition (which is hard to read).
Anyways, a few side notes:
The snippet you show might have a pitfall if you have an odd number of lines and Set-StrictMode -Version Lastest enabled:
Set-StrictMode -Version Latest
toHash "key1`nvalue1`nkey2"
OperationStopped:
Line |
5 | $hash[$arr[$i]] = $arr[$i + 1]
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Index was outside the bounds of the array.
Name Value
---- -----
key1 value1
The variable neme $content, suggests that you reading the data from a file, possibly with Get-Connent. If that is indeed the case you might consider to stream the input (which conserves memory):
$Content -split '\r?\n' | # Get-Content .\Data.txt
Foreach-Object -Begin {
$Hash = #{}
$Key = $Null
} -Process {
if (!$Key) {
$Key = $_
}
else {
$Hash[$Key] = $_
$Key = $Null
}
} -End {
$Hash
}
And if you create use an [ordered] dictionary, you might even put this is a single statement like:
$Content -split '\r?\n' |Foreach-Object { $h = [Ordered]#{} } { if (!$h.count -or $h[-1]) { $h[$_] = $Null } else { $h[$h.Count - 1] = $_ } } { $h }
(Note that -as with the propose in the question- I do not take into account that there might be empty lines in the input data)
See also PowerShell issue: #13817 Enhance hash table syntax

Can an array variable defined in Azure DevOps "variable group"

I want to define some variables in Azure devops "variable group" which will be used in Powershell, but when the variable type is string it works, but some is array or object went wrong. mine look like below. left is the name,right is the value
vmAlertedArray_backup => #("wbubuntu","wbubuntu2")
1.when in azure devops script I use, it went wrong
$vmAlertedArray_backup = $env:vmAlertedArray_backup
foreach($c in $vmAlertedArray_backup){
Write-Host "$c"
}
2.below in powershell in local works
$vmAlertedArray_backup = #("wbubuntu","wbubuntu2")
foreach($c in $vmAlertedArray_backup){
Write-Host "$c"
}
Can any one show some experience about this? thanks
It is suggested to only pass variables as string. If you want to pass an object to other tasks, you can use "ConvertTo-Json -Compress" to convert it to a json string.
$objectString = $object | ConvertTo-Json -Compress
Write-Host "##vso[task.setvariable variable=objectString;]$objectString"
And in the next PS task, you can pass it as environment variable. But, please enclose the variables in single quotes.
And then you can use "ConvertFrom-Json" to convert the string to an object.
$getFromEnv = $env:objectString | ConvertFrom-Json
foreach( $obj in $getFromEnv){
Write-Host ("displayName:{0} Id:{1}" -f $obj.displayName, $obj.Id)
}
I just pass the variable in as a string and then split it to create an array in PowerShell
Variable = Prod1,Prod2,Prod3
$array = $variable.Split(',)
If need be you can add a Trim to the end in case there are spaces
Variable = Prod1,Prod2 ,Prod3
$array = $workspaces.Split(',').trim()

How to export value output without '#{}' after string replacement?

I'm trying to export forward list from Exchange 365 and remove "smtp:" string from output.
Here is PS code for Exchange 365 forwards list:
$forwards = Get-Mailbox –ResultSize Unlimited |
where {($_.ForwardingSmtpAddress –ne $null)} |
select identity, *forward*
$result = $forwards -replace "smtp:",""
$result
My $forwards value has format:
PS> $forwards
Identity DeliverToMailboxAndForward ForwardingAddress ForwardingSmtpAddress
-------- -------------------------- ----------------- ---------------------
name.surname1 True smtp:name.surname1#domain.com
name.surname2 True smtp:name.surname2#domain.com
name.surname3 True smtp:name.surname3#domain.com
I managed to remove that smtp: text with command:
$result = $forwards -replace "smtp:",""
But I get such ugly output for that variable:
PS> $result
#{Identity=name.surname1; DeliverToMailboxAndForward=True; ForwardingAddress=; ForwardingSmtpAddress=name.surname1#domain.com}
#{Identity=name.surname2; DeliverToMailboxAndForward=True; ForwardingAddress=; ForwardingSmtpAddress=name.surname2#domain.com}
#{Identity=name.surname3; DeliverToMailboxAndForward=True; ForwardingAddress=; ForwardingSmtpAddress=name.surname3#domain.com}
How to get rid of that #{} and present it right way as it was in $forwards variable? Maybe there is better way to remove smtp: from first value $forwards?
You should also be able to use calculated properties:
$forwards = Get-Mailbox –resultSize unlimited |
where { $_.ForwardingSmtpAddress –ne $null } |
select #{Name="Identity";Expression={$_.Identity}},
DeliverToMailboxAndForward, ForwardingAddress,
#{Name="ForwardingSmtpAddress";Expression={$_.ForwardingSmtpAddress -replace "smtp:",""}}
I don't have the means to test this right now, though.
Instead of creating a new variable it might be easier to modify the existing objects in your array. You need to do the replacement on each ForwardingSmtpAddress property:
$forwards | Foreach-Object {
$_.ForwardingSmtpAddress = $_.ForwardingSmtpAddress -replace "smtp:", ""
}
After this, just echoing $forwards to the screen should show you the updated values.
What would be the result when you use this snippet?
$forwards = Get-Mailbox –resultSize unlimited |
where {$_.ForwardingSmtpAddress –ne $null} |
select Identity, DeliverToMailboxAndForward, ForwardingAddress,
#{Name='ForwardingSmtpAddress';Expression={$_.ForwardingSmtpAddress.ToString().Replace('smtp:', $null)}}
If you don't wan't the #{} maybe you could convert or export it to a CSV format.
Export-Csv -Delimiter ';'
ConvertTo-Csv -Delimiter ';'

Get-AzureRmWebApp: filtering results has unexpected behavior

I type the following in Powershell, to list the names of all of my azure web applications:
Get-AzureRmWebApp | % { $_.Name }
It outputs:
coolum-exercise-web-app
practice-web-app
AzureSandbox
But then I want to filter this output on the name. I type this:
Get-AzureRmWebApp | ? { $_.Name -like "coolum-exercise-web-app" } | % { $_.Name }
I expect to see only one output. Instead I see
coolum-exercise-web-app
practice-web-app
AzureSandbox
Why didn't the name filter get applied?
If I use the -Name parameter directly on Get-AzureRmWebApp it works:
Get-AzureRmWebApp -Name "coolum-exercise-web-app" | % { %_.Name }
Outputs:
coolum-exercise-web-app
But why does where-object fail to apply the filter as expected?
And here's some really puzzling behavior: if you wrap Get-AzureRmWebApp in brackets, the filter works as you would expect it to.
(Get-AzureRmWebApp) | ? { $_.Name -like "coolum-exercise-web-app" } | % { $_.Name }
Outputs:
coolum-exercise-web-app
Can anyone explain this behavior? Why would enclosing the command in brackets make the filtering work?
Please try with: (notice the brackets)
(Get-AzureRmWebApp) | ? { $_.Name -like 'cool*' }
Looks like the whole where clause is considered as the default named parameter to Get-AzureRmWebApp. That's why you have to seperate the CmdLet from the where clause with brackets.
Actually Get-AzureRmWebApp returns a list, whereas other CmdLet like Get-AzureRmVM returns a single object.
Get-AzureRmWebApp | gm
Get-AzureRmVM | gm
This is a known bug: #1544 Get-AzureRmWebApp - unable to pipe into select-object
The results of Get-AzureRmWebApp is a list. You would expect each item of the list to be sent through the pipe item-by-item. Instead, the entire list gets sent through the pipe once, as a single object.
To demonstrate:
Get-AzureRmWebApp | % { $_.GetType().FullName }
Displays
System.Collections.Generic.List`1[[Microsoft.Azure.Management.WebSites.Models.Site, Microsoft.Azure.Management.Websites, Version=1.0.0.2, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]
While
(Get-AzureRmWebApp) | % { $_.GetType().FullName }
Displays
Microsoft.Azure.Management.WebSites.Models.Site
Microsoft.Azure.Management.WebSites.Models.Site
Microsoft.Azure.Management.WebSites.Models.Site
The bug happens because the underlying C# code invokes WriteObject(sendToPipeline = list), when it should invoke WriteObject(sendToPipeline = list, enumerateCollection = true)
The act of wrapping the call in brackets assigns the returned list to a local temporary object. This local temporary object then behaves like a normal list.
I hope the Azure team fix this, because there will be unintended consequences for hapless automation script writers.
For example, my original call:
Get-AzureRmWebApp | ? { $_.Name -like "coolum-exercise-web-app" } | % { $_.Name }
gets interpreted as "If any of the values has a Name like coolum-exercise-web-app, then display all of the values."
Edit (March 2019)
I have tested this with the Azure Az Powershell Modules and I can see this problem has been fixed.

How can I an Object's Property to a String in Powershell

I'm pretty familiar with PHP, Javascript, etc but I'm new to Powershell. I'm trying to get IP addresses and Mac addresses from all the computer's in an active directory. I came across a script that gets an object with all the computer names a lists them through a foreach loop. Inside that loop, I'm trying to run the following:
$colItems = GWMI -cl "Win32_NetworkAdapterConfiguration" -name "root\CimV2" `
comp $objComputer.name -filter "IpEnabled = TRUE"
Obviously, this isn't working since it can't take data from the pipeline. Is there away to take the name property and convert it into a string variable to use within the Get-WmiObject? I've tried declaring a string variable with that $objComputer.name as the value and tried $($objComputer.name), but neither did it for me. Any help would be greatly appreciated.
i think you need a hyphen in front of comp...
$colItems = GWMI -cl "Win32_NetworkAdapterConfiguration" -name "root\CimV2" -comp $objComputer.name -filter "IpEnabled = TRUE"
that could be a copy and paste error...
This works for me though (using a dot):
$colItems =GWMI -cl "Win32_NetworkAdapterConfiguration" -name "root\CimV2" -comp . -filter "IpEnabled = TRUE"
using $objComputer though you could do this
$objComputer = #{ "name" = "." }
Matt
Unfortunately Get-WmiObject doesn't accept pipeline input. Altough passing $objComputer.name is perfectly valid (as long as $objComputer is an object that has a name member) you can assign the name value to a vraible and pass the variable to the ComputerName property.
foreach($objComputer $computers)
{
$name = $objComputer.name
$colItems = GWMI -cl Win32_NetworkAdapterConfiguration -comp $name -filter "IpEnabled = TRUE"
$colItems
...
}

Resources