I'm pulling the hostnames from all computers in an AD domain and the current command formats it in url form with the hostname at the end. I just need the hostnames so I'd like to strip everything to the left of the last forward slash.
(([adsi]"WinNT://$((Get-WMIObject Win32_ComputerSystem).Domain)").Children).Where({$_.schemaclassname -eq 'computer'}) | %{ $_.Path }
It's outputting as it should, I just happen to just need the hostname, so instead of WinNT://subdomain.somedomain.local/hostname I just got hostname which I would then redirect to an output file.
You can use the -Split operator to help retrieve the data:
"WinNT://subdomain.somedomain.local/hostname" -Split "/" | Select-Object -Last 1
-Split "/" separates the value into an array of substrings using / as a delimiter. You can access the resulting parts using array indexes or Select-Object. Since you want the last value, you could alternatively access [-1] index of the resulting array (("WinNT://subdomain.somedomain.local/hostname" -Split "/")[-1]).
See About Split for more information and examples.
Just posting another option, and something else that may be useful. You can also split strings by their last index, which is the last time a character appears in it. From there you can use the Substring method to select the remainder of the string.
$lio = "WinNT://subdomain.somedomain.local/hostname".LastIndexOf('/')
"WinNT://subdomain.somedomain.local/hostname".Substring($lin + 1) # +1 to not include the slash
You can see all the methods for a string here
For things like this, I would also suggest looking at the ActiveDirectory module. You can run Get-ADComputer and select specific fields really easily.
Related
I have a PowerShell script that imports a CSV file, filters out rows from two columns and then concatenates a string and exports to a new CSV file.
Import-Csv "redirect_and_canonical_chains.csv" |
Where { $_."Number of Redirects" -gt 1} |
Select {"Redirect 301 ",$_.Address, $_."Final Address"} |
Export-Csv "testing-export.csv" –NoTypeInformation
This all works fine however for the $_.Address value I want to strip the domain, sub-domain and protocol etc using the following regex
^(?:https?:\/\/)?(?:[^#\/\n]+#)?(?:www\.)?([^:\/\n]+)
This individually works and matches as I want but I am not sure of the best way to implement when selecting the data (should I use $match, -replace etc) or whether I should do it after importing?
Any advice greatly appreciated!
Many thanks
Mike
The best place to do it would be in the select clause, as in:
select Property1,Property2,#{name='NewProperty';expression={$_.Property3 -replace '<regex>',''}}
That's what a calculated property is: you give the name, and the way to create it.Your regex might need revision to work with PowerShell, though.
I've realized now that I can just use .Replace in the following way :)
Select {"Redirect 301 ",$_.Address.Replace('http://', 'testing'), $_."Final Address"}
Based on follow-up comments, the intent behind your Select[-Object] call was to create a single string with space-separated entries from each input object.
Note that use of Export-Csv then makes no sense, because it will create a single Length column with the input strings' length rather than output the strings themselves.
In a follow-up comment you posted a solution that used Write-Host to produce the output string, but Write-Host is generally the wrong tool to use, unless the intent is explicitly to write to the display only, thereby bypassing PowerShell's output streams and thus the ability to send the output to other commands, capture it in a variable or redirect it to a file.
Here's a fixed version of your command, which uses the -join operator to join the elements of a string array to output a single, space-separated string:
$sampleCsvInput = [pscustomobject] #{
Address = 'http://www.example.org/more/stuff';
'Final Address' = 'more/stuff2'
}
$sampleCsvInput | ForEach-Object {
"Redirect 301 ",
($_.Address -replace '^(?:https?://)?(?:[^#/\n]+#)?(?:www\.)?([^:/\n]+)', ''),
$_.'Final Address' -join ' '
}
Note that , - PowerShell's array-construction operator - has higher precedence than the -join operator, so the -join operation indeed joins all 3 preceding array elements.
The above yields the following string:
Redirect 301 /more/stuff more/stuff2
I have a CSV file containing user aliases in first.last name format.
I am attempting to pull these aliases one-by-one and combine them with our domain, to create their email address.
Here is my code:
$CSV = Import-CSV "\\this\is\thepath\to\the\csv.csv"
$domain = "#domain.co.uk"
$CSV.Alias | ForEach-Object (
Write-Host ($CSV.Alias + $domain)
)
the output I need, is:
John.Doe#domain.co.uk Jane.Doe#domain.co.uk John.Smith#domain.co.uk
However, this is what's being output:
John.Doe Jane.Doe John.Smith #domain.co.uk
Try this:
$CSV = Import-CSV '\\this\is\thepath\to\the\csv.csv'
$domain = '#domain.co.uk'
$CSV.Alias | ForEach-Object {
Write-Host $_ + $domain
}
If I apply it to this input file:
Alias
John.Doe
Jane.Doe
John.Smith
I get this output.
John.Doe#domain.co.uk
Jane.Doe#domain.co.uk
John.Smith#domain.co.uk
All I did was to correct two bugs in your attempt, the two bugs that were pointed out in the comments to the question. Plus I made two cosmetic changes.
One cosmetic change was to use single quotes in a couple of places where you used double quotes. If you don't need the transformations that double quotes invoke, don't use them. Use single quotes instead. This is just defensive coding.
Another cosmetic change was to remove the parentheses surrounding the argument to Write-Host. It works without those parentheses. One might argue that the parentheses should be in there anyway, to make it easier to read. OK.
I currently have a series of Dyanmic Distribution Groups that I want to edit the recipient filter on. Our company is based by location number, which is a 4 digit number. This number is part of the display name of the dynamic distribution group...example webcontact_1234_DG....1234 would be the 4 digit center number. I am wanting to replace the recipient filter to have office -eq (1234) but have it pull the number from the display name. All display names are going to be the same number of characters before the 4 digit center number, for example, webcontact_1234_DG, webcontact_2345_DG, webcontact_3456_DG, etc.
I have a replace code but it changed the office location to null.
Here is the code that I am using:
$groups=Get-DynamicDistributionGroup -filter {alias -like "webcontact*"}
foreach ($group in $groups) {
$locationcode=$($group.alias).tostring.replace("\\D", "")
set-dynamicdistributiongroup $group -recipientfilter {((((office -eq $locationcode) -and
(have the recipent filter here but can't display due to confidential information) -and
(RecipientType -eq 'UserMailbox') -and
(-not(RecipientTypeDetails -eq 'RoomMailbox')) -and
(-not(RecipientTypeDetails -eq 'SharedMailbox'))))}
}
This is the best answer I can come up with based on the given information. I assume you are having a problem getting that number out of your webcontact_1234_DG, I would use regex to get those numbers out and into another variable.
$locationcode = [regex]::Match($group.alias,'^[^_]+_([^_]+)_[^_]+$').Groups[1].Value
The above code will grab everything in between the two underscores.
Try that and let me know.
It's easiest to use the -split operator to extract the number (text) from your values[1]:
$locationcode = ($group.Alias -split '_')[1]
-split '_' returns the array of tokens that result when you split the input string by _ chars., and [1] returns the 2nd token, which is the desired location number.
Simple example:
PS> ('webcontact_3456_DG' -split '_')[1]
3456
Alternatively, a corrected version of your own attempt (see below) would use the -replace operator:
PS> 'webcontact_3456_DG' -replace '\D' # remove all non-digit chars.
3456
As for what you tried:
$($group.alias).tostring.replace("\\D", "")
The [string] type's .Replace() searches by literal strings, so the search for \\D in your names will fail, and no replacement will occur.
Additionally, note that PowerShell's escape character is ` (backtick), not \, and that \ therefore doesn't require escaping: in PowerShell "\\D" literally becomes \\D.
As an aside: There is generally no need to put $(...) around expressions.
[1] You could also use the [string] type's .Split() .NET method in this simple case, but I suggest using the far more flexible -split PS operator as a matter of habit.
I am attempting to isolate and return a small variable string from a larger string.
I am struggling because the larger string I am extracting from is in list format. I can split this into substrings successfully, but I do not know how to select one of these substrings without returning the entire string. The string is generated by a command line process.
$StringList
AppTitle1.1.1221.aaa111
AppSubTitle
AnotherAppTitle1.1.1221.aaa111
AnotherAppSubTitle
...and so on
I can split the list string into substrings by line using regular expressions to split at whitespace (there is no whitespace within any given line).
$StringList -split "\s"
Once I have split the string into the desired substrings, however, I am not sure how to select the desired substring. The length of the list (i.e. the number of apps present in it) and the location of the app I need to retrieve the title of within that list are entirely variable, so I cannot simply use substring reference numbers. I've tried several approaches to selecting the substring, but each has simply returned the entire string, or nothing at all.
Here are two approaches I've attempted. The first returns the entire string list and the second returns nothing.
$DesiredAppTitle = Select-String -InputObject $StringList -Pattern "AnotherAppTitle"
or
$DesiredAppTitle = foreach ($_.substring in $StringList)
{
if ($_.substring -contains "AnotherAppTitle")
{
return $_.name
}
}
What I'd like for it to return is:
AnotherAppTitle1.1.1221.aaa111
I'm sure there are a million ways to do this, so if neither of my approaches seems like a good fit, I'm open to other suggestions. Any assistance would be greatly appreciated. Thanks in advance!
# Multi-line input string.
$StringList = #'
AppTitle1.1.1221.aaa111
AppSubTitle
AnotherAppTitle1.1.1221.aaa111
AnotherAppSubTitle
'#
# Split it into whitespace-separated tokens.
$tokens = -split $StringList
# Match the token of interest.
$tokens -match '^AnotherAppTitle'
The above yields:
AnotherAppTitle1.1.1221.aaa111
Note the use of regex-matching operator with anchor ^ to ensure that the search term matches at the start of a token, and the use of the unary form of the -split operator, which splits the input by any nonempty whitespace runs.
As for what you tried:
If you pass a multi-line string to Select-String, it is considered a single "line" and, in case of a match, that whole "line" is output.
foreach ($_.substring in $StringList) won't even run, because $_.substring is not a valid iteration variable (you shouldn't use $_, which is an automatic variable, as an enumeration variable at all, and the .substring access breaks the syntax).
If you used $_ instead of $_.substring, the loop would technically work (even though, again, $_ shouldn't be used as an iteration variable), but the loop would only execute once, for the entire multi-line string.
Even if $_.substring did refer to a line (it doesn't), -contains is the wrong operator to use, because it tests if a LHS collection contains the RHS value in full.
Also, use break to exit a loop, not return.
Using the -match approach as demonstrated at the top is the better approach, but if you did want to solve this with a foreach loop:
$DesiredAppTitle = foreach ($token in -split $StringList) {
if ($token -match '^AnotherAppTitle') { $token; break }
}
I am trying to create a Powershell script which wraps quotes around each columns of the file on export to CSV. However the Export-CSV applet only places these where they are needed, i.e. where the text has a space or similar within it.
I have tried to use the following to wrap the quotes on each line but it ends up wrapping three quotes on each column.
$r.SURNAME = '"'+$r.SURNAME+'"';
Is anyone able to share how to forces these on each column of the file - so far I can just find info on stripping these out.
Thanks
Perhaps a better approach would be to simply convert to CSV (not export) and then a simple regex expression could add the quotes then pipe it out to file.
Assuming you are exporting the whole object $r:
$r | ConvertTo-Csv -NoTypeInformation `
| % { $_ -replace ',(.*?),',',"$1",' } `
| Select -Skip 1 | Set-Content C:\temp\file.csv
The Select -Skip 1 removes the header. If you want the header just take it out.
To clarify what the regex expression is doing:
Match: ,(.*?),
Explanation: This will match section of each line that has a comma followed by any number of characters (.*) without being greedy (? : basically means it will only match the minimum number of characters that is needed to complete the match) and the finally is ended with a comma. The parenthesis will hold everything between the two commas in a match variable to be used later in the replace.
Replace: ,"$1",
Explanation: The $1 holds the match between the two parenthesis mention above in the match. I am surrounding it with quotes and re-adding the commas since I matched on those as well they must be replaced or they are simply consumed. Please note, that while the match portion of the -replace can have double quotes without an issue, the replace section must be surrounded in single quotes or the $1 gets interpreted by PowerShell as a PowerShell variable and not a match variable.
You can also use the following code:
$r.SURNAME = "`"$($r.SURNAME)`""
I have cheated to get what I want by re-parsing the file through the following - guess that it acts as a simple find and replace on the file.
get-content C:\Data\Downloads\file2.csv
| foreach-object { $_ -replace '"""' ,'"'}
| set-content C:\Data\Downloads\file3.csv
Thanks for the help on this.