Not Match each element of $mylist - list

I would like to list all uninstall entries and ignore some entries with a whitelist.
Listing the uninstall entries works, but I don't understand how to use $mylist to ignore "app1","app2","app3".
$mylist = #("app1","app2","app3")
Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall,
HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall |
Get-ItemProperty |
Where-Object {$_.DisplayName -notmatch $mylist } |
Select-Object -Property DisplayName, UninstallString
Have you an idea?

For checking if a list doesn't contain a particular element use the -notcontains or -notin operator:
... | Where-Object { $mylist -notcontains $_.DisplayName } | ...
or
... | Where-Object { $_.DisplayName -notin $mylist } | ...
Note that the -notin operator isn't available prior to PowerShell v3.
For doing partial matches of one list against another you need something like this:
... | Where-Object {
$name = $_.DisplayName;
-not ($mylist | Where-Object {$name -like "*$_*"})
} | ...

You can construct a regex pattern from the list, and then use the -match operator:
# Construct pattern
$pattern = #($mylist|ForEach-Object {[regex]::Escape($_)}) -join '|'
# Use pattern with -match
... |Where-Object { $_.DisplayName -match $pattern }

Related

Keep the $character in regular expression replace

Two problems of regular replace
1.need to keep the front $character in the replacement result
2.Skipping the first two lines and the last line is not valid
Code:
$str = #'
#$start1 Random characters
#$start2 Random characters
$p1.AppendBreak($BreakType.LineBreak)
$doc.Protect($ProtectionType.AllowOnlyRevisions, "123")
$footerPara.AppendField("page", $FieldType.FieldPage)
$footerParagraph.AppendField("number of pages", $FieldType.FieldSectionPages)
$txtWatermark.Layout = $WatermarkLayout.Diagonal
$tr1.CharacterFormat.Border.BorderType = $BorderStyle.DashDotStroker
$stri.CharacterFormat.TextBackgroundColor = $Color.LightGray
$document.LoadFromFile(".\Template_HtmlFile.html", $FileFormat.Html, $XHTMLValidationType.None)
$docObject.DocumentObjectType -eq $DocumentObjectType.Picture
$document.Sections[0].Paragraphs[0].InsertSectionBreak($SectionBreakType.NoBreak)
$footerParagraph.Format.HorizontalAlignment = $Spire.Doc.Documents.HorizontalAlignment.Right
#end Random characters
'#
$str | Foreach-Object {
$_ -replace '\$\w+\.(\w+)', '"$1"'
} | Set-Content .\ok.txt
<# -Skip -SkipLast not valid
$str | Foreach-Object {
$_ -replace '\$\w+\.(\w+)', '"$1"'
} | Select-Object -Skip 2 | Select-Object -SkipLast 1 | Set-Content .\ok.txt
#>
Expected results:
At least for your example here string, you need to break it into a string array. Then for the replacement I was only successful when capturing both the beginning and the desired changed text.
$str -split '\r?\n' | Select-Object -Skip 2 |
Select-Object -SkipLast 1 | Foreach-Object {
$_ -replace '(^.+?)\$.+\.(\w+)', '$1"$2"'
} | Set-Content .\ok.txt
Contents of ok.txt
$p1.AppendBreak("LineBreak")
$doc.Protect("AllowOnlyRevisions", "123")
$footerPara.AppendField("page", "FieldPage")
$footerParagraph.AppendField("number of pages", "FieldSectionPages")
$txtWatermark.Layout = "Diagonal"
$tr1.CharacterFormat.Border.BorderType = "DashDotStroker"
$stri.CharacterFormat.TextBackgroundColor = "LightGray"
$document.LoadFromFile(".\Template_HtmlFile.html", "None")
$docObject.DocumentObjectType -eq "Picture"
$document.Sections[0].Paragraphs[0].InsertSectionBreak("NoBreak")
$footerParagraph.Format.HorizontalAlignment = "Right"

Filter list from multiple values

I have this line:
$output.GetEnumerator() | Where-Object { $_.ItemPath -notlike "*.zip" } | Select ItemPath
Example output:
ItemPath
--------
\\devws04
\\devws04\c$
\\devws04\c$\share
\\devws04\c$\share\Dieser ORdner ist offline erstellt worden
\\devws04\c$\share\FileOfflineMode - Copy.txt
\\devws04\c$\share\FileOfflineMode.txt
\\devws04\c$\share\Personal
\\devws04\c$\share\Personal\Okey Cuuus.txt
\\devws04\c$\share\Portfolio.txt
The line excludes path values which contain "*.zip". It works but I want to use a variable at this place and not append everything to the same line with "and".
I tried following:
$ignoreFiles = #("*.zip", "*.psd")
$output.GetEnumerator() | Where-Object { $_.ItemPath -notin $ignoreFiles } | Select ItemPath
And several other snippets but none of them worked. It did just nothing to the result. Any hint appreciated!
This is the full output:
ItemPath
--------
\\devws04
\\devws04\c$
\\devws04\c$\share
\\devws04\c$\share\Dieser ORdner ist offline erstellt worden
\\devws04\c$\share\Dieser ORdner ist offline erstellt worden\MeineofflineDateien.zip
\\devws04\c$\share\FileOfflineMode - Copy.txt
\\devws04\c$\share\FileOfflineMode.txt
\\devws04\c$\share\Personal
\\devws04\c$\share\Personal\Okey Cuuus.txt
\\devws04\c$\share\Portfolio.txt
EDIT:
This is the actual code and my goal is to do a csv-export but before I want to filter the values like described above:
$ignoreFiles = "\.zip|\.psd"
#$ignoreFiles = #("*.zip", "*.psd")
$query = Get-WmiObject -query "SELECT * FROM Win32_OfflineFilesItem"
$hostName = [System.Net.Dns]::GetHostName()
$user = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
$output = #()
$query | ? {
$output += [PSCustomObject] #{
User = $user
Hostname = $hostName
ItemPath = $_.ItemPath
}
}
$output | Export-CSV $outputPath -NoTypeInformation # ONLY EXPORT OBJECTS WHERE $_.ItemPath does not contain one of the values from $ignoreFiles!
You could also use regex to help you with the challenge that you face:
$regex = "\.zip|\.psd"
$paths = $output.GetEnumerator() | Select-Object ItemPath
$paths.ItemPath -notmatch $regex
Updated with extra answer
I would say this should do the trick
$output = $output | Where-Object {$_.ItemPath -notmatch $ignoreFiles }
$output | Export-CSV $outputPath -NoTypeInformation # ONLY EXPORT OBJECTS WHERE $_.ItemPath does not contain one of the values from $ignoreFiles!
not sure what $output is,
But using a variable should work exactly the same:
$ext = "*.zip"
$output | Where-Object { $_.ItemPath -notlike $ext } | Select ItemPath
You could also use -notin for an array of things, depending on the input:
gci | Where-Object { $_.Extension -notin ($ext, ".7z") } | Select FullName

Get the numbers after ":" and count them with the help of powershell

Could someone please help me with extracting and counting the numbers from a text file with PowerShell?
Example: c:\temp\1.txt is some text with semicolon and numbers after them. I need to sum all of these numbers.
blablabl:5 dzfdsfdsfsdfsf:10
sdfsdfsdfdffs:8sdfsfsfdsfdsf:111
5+10+8+111...
What I've tried so far:
$LogText = "C:\temp\1.txt"
[regex]$Regex = "\. (\d+):[1]"
$Matches = $Regex.Matches($LogText)
$Matches | ForEach-Object {
Write-Host $Matches
}
#$array = #()
#$array = new-object collections.arraylist
$array = while ($Matches.Success) {
Write-Host $array[i++]
}
# -------------------------------------------------------------------
$text = Get-Content "C:\temp\1.txt"
[regex]$Regex = "\d"
$Matches = $Regex.Matches($text)
# -------------------------------------------------------------------
$pos = $text.IndexOf(":")
$rightPart = $text.Substring($pos+1)
Write-Host $rightPart
Use Select-String to extract the matches from the file and Measure-Object to do the calculation.
Select-String -Path 'C:\temp\1.txt' -Pattern '(?<=:)\d+' -AllMatches |
Select-Object -Expand Matches |
Select-Object -Expand Value |
Measure-Object -Sum |
Select-Object -Expand Sum
(?<=:) is a positive lookbehind assertion to match the colon preceding the number without making it part of the match.
Try it like that:
$txt=
#"
blablabl:5 dzfdsfdsfsdfsf:10
sdfsdfsdfdffs:8sdfsfsfdsfdsf:111
"#
[regex]$Regex = '\d+'
$sum=0;
$Regex.Matches($txt) | ForEach-Object {
$val = [int]$_.Value
$val
$sum+=$val
}
$sum

PowerShell Regex DisplayName

I need to put a bunch of users through a regex query that look for 'IM' or '(IM)' at the end of their DisplayName and then removes it. I'll be exporting first of course for backup.
I'm have used the .contains method but if I use that any Tim's or Imogen's might get a little annoyed at me.
$users = Get-DistributionGroupMember 'DGName' | ? { $_.RecipientType -eq 'UserMailbox' }
$mailboxes = $users | Get-Mailbox
$output = #()
$mailboxes | Select-Object Alias, DisplayName | Export-Csv D:\Scripts\PreDisplayNames.csv -NoTypeInformation
foreach ($mb in $mailboxes){
if ($mb.DisplayName.EndsWith(" (IM)")){
$newString = $mb.DisplayName.TrimEnd(" (IM)")
$newStringTD = $mb.DisplayName.TrimEnd(" (IM)") + " (TD)"
$resultstring = "Setting DisplayName to $newString"
$mb | Set-Mailbox -DisplayName $newString -WhatIf
}
elseif($mb.DisplayName.EndsWith(" IM")){
$newString = $mb.DisplayName.TrimEnd(" IM")
$newStringTD = $mb.DisplayName.TrimEnd(" (IM)") + " (TD)"
$resultstring = "Setting DisplayName to $newString"
$mb | Set-Mailbox -DisplayName $newString -WhatIf
}
else{
$newString = 'DNIncorrect'
$resultstring = 'Incorrect DisplayName'
}
$props = [ordered]#{
'DisplayName' = $mb.DisplayName
'NewDisplayName' = $newString
'NewDisplayName TD' = $newStringTD
}
$object = New-Object -TypeName PSObject -Property $props
$output += $object
}
$output | Export-Csv "D:\scripts\DisplayNames.csv" -NoTypeInformation
Theres no need for a regex here, just use a -like to filter your objects when you collect the mailboxes
$mailboxes = $users | Get-Mailbox | Where-object {($_.DisplayName -like "*IM") -or ($_.DisplayName -like "*(IM)")}
If you still wanted a regex I normally use the following to generate a regex for specific words. It may work for you situation.
$Eliminate = #("bak", "error", "research","Retry")
[regex]$eliminate_regex = '(?i)(' + (($Eliminate | foreach { [regex]::escape($_) }) -join "|") + ')'

powershell regular expressions

quick one:
$logFile="D:\Code\functest\1725.log"
function getTime($pattern) {
Get-Content $logFile | %{ if ($_.Split('\t') -match $pattern) {$_} }
}
getTime("code")
gives me
simple 17-Feb-2011 10:45:27 Updating source code to revision: 49285
simple 17-Feb-2011 10:54:22 Updated source code to revision: 49285
but if I change the print value from
$_
to
$matches
I get nothing. I thought this array should have been created automatically? probably something silly, but this is my first day of using powershell :-)
EDIT: what I want to return is
Get-Date (column 2 of the matching line)
Your call to Split() is using C# conventions to escape the t to specify a tab character. In PowerShell, you use a single backtick e.g. $_.Split("`t"). Also -match is behaving a bit differently on an array like this so have it operate on each individual string like so:
Get-Content $logFile | Foreach {$_.Split("`t")} | Where { $_ -match $pattern }
There's also a sort of hidden trick here with Get-Content where you can get it to split for you:
Get-Content $logFile -del "`t" | Where { $_ -match $pattern }
Update: based on the updated question, try something like this:
gc $logFile | % {$cols = $_.Split("`t"); if ($cols[2] -match $pattern) {$cols[1]}}
Keeping in mind that arrays are 0-based in PowerShell. If the text is already in a DateTime format that PowerShell/.NET understand, you can just cast it to a DateTime like so [DateTime]$cols[1].
The $_.Split('\t') is breaking it.
First, it's breaking on every letter "t", not at tabs.
Second, it return a array that confounds -match.
With the following code:
Get-Content $logFile | %{ if ($_ -match $pattern) { $matches } }
getTime("code") would return:
Name Value
---- -----
0 code
0 code
This would allow to search with regular expressions, as in
$answerArray = getTime("(\t)(\d+)")
$digitsOfSecondResult = $answerArray[1][2]
Write-Output $digitsOfSecondResult
If you just want to print the lines that match the pattern, try:
Get-Content $logFile | %{ if ($_ -match $pattern) { $_} }
To get the date:
function getTime($pattern) {
Get-Content $logFile | %{ if ($_ -match $pattern) { Get-Date $matches[1] } }
}
getTime("`t(.+)`t.*code")
Or:
function getTime($pattern) {
Get-Content $logFile | %{ if ($_ -match "`t(.+)`t.*$pattern") { Get-Date $matches[1] } }
}
getTime("code")