Using "starts with" in powershell script instead of contains? - powershell

In my current powershell script I have hash table with values. Am using
this syntax
$x = $f.contains("$k")
but I figured recently that am having problems with this approach I was wondering if powershell has something that says "starts with," or related, that would search thru the hash table with "starts with" instead of contains
Example of the hash table:
"bio.txt" = "server1\datafiles\bio";
etc.......
EDIT Sample from comments
foreach ($key in $filehash.keys) {
$path = $filehash.get_Item($key)
$filecount = 0
foreach ($file in $FileArray) {
if ($file.LastWriteTime -lt($(GetDate).adddays(-1))) {
[string] $k = $key.ToLower()
[string] $f = $file.name.ToLower()
if ($x = $f.contains("$k")) { }
}
}
}

Try using -like to check if a string starts with yourvalue. I rewrote your sample in the comments to use it:
$filehash.GetEnumerator() | foreach {
#$_ is now current object from hashtable(like foreach)
#$_.key is key and $_.value is path
$filecount = 0
foreach ($file in $FileArray) {
if ( ($file.LastWriteTime -lt $((Get-Date).AddDays(-1))) -and ($file.name -like "$($_.Key)*") ) {
#process file
}
}
}

Related

Comparing two text files and output the differences in Powershell

So I'm new to the Powershell scripting world and I'm trying to compare a list of IPs in text file against a database of IP list. If an IP from (file) does not exist in the (database) file put it in a new file, let's call it compared.txt. When I tried to run the script, I didn't get any result. What am I missing here?
$file = Get-Content "C:\Users\zack\Desktop\file.txt"
$database = Get-Content "C:\Users\zack\Desktop\database.txt"
foreach($line1 in $file){
$check = 0
foreach($line2 in $database)
{
if($line1 != $line2)
{
$check = 1
}
else
{
$check = 0
break
}
}
if ($check == 1 )
{
$line2 | Out-File "C:\Users\zack\Desktop\compared.txt"
}
}
There is a problem with your use of PowerShell comparison operators unlike in C#, equality and inequality are -eq and -ne, and since PowerShell is a case insensitive language, there is also -ceq and -cne.
There is also a problem with your code's logic, a simple working version of it would be:
$database = Get-Content "C:\Users\zack\Desktop\database.txt"
# iterate each line in `file.txt`
$result = foreach($line1 in Get-Content "C:\Users\zack\Desktop\file.txt") {
# iterate each line in `database.txt`
# this happens on each iteration of the outer loop
$check = foreach($line2 in $database) {
# if this line of `file.txt` is the same as this line of `database.txt`
if($line1 -eq $line2) {
# we don't need to keep checking, output this boolean
$true
# and break the inner loop
break
}
}
# if above condition was NOT true
if(-not $check) {
# output this line, can be `$line1` or `$line2` (same thing here)
$line1
}
}
$result | Set-Content path\to\comparisonresult.txt
However, there are even more simplified ways you could achieve the same results:
Using containment operators:
$database = Get-Content "C:\Users\zack\Desktop\database.txt"
$result = foreach($line1 in Get-Content "C:\Users\zack\Desktop\file.txt") {
if($line1 -notin $database) {
$line1
}
}
$result | Set-Content path\to\comparisonresult.txt
Using Where-Object:
$database = Get-Content "C:\Users\zack\Desktop\database.txt"
Get-Content "C:\Users\zack\Desktop\file.txt" | Where-Object { $_ -notin $database } |
Set-Content path\to\comparisonresult.txt
Using a HashSet<T> and it's ExceptWith method (Note, this will also get rid of duplicates in your file.txt):
$file = [System.Collections.Generic.HashSet[string]]#(
Get-Content "C:\Users\zack\Desktop\file.txt"
)
$database = [string[]]#(Get-Content "C:\Users\zack\Desktop\database.txt")
$file.ExceptWith($database)
$file | Set-Content path\to\comparisonresult.txt

Check for strong string matching "powershell"

I get an element from the array, I check whether the line exists in the file or not. If it exists, then I change it to an element from the second array by index. Everything works fine. The problem is that if a string from an array is similar to a string in a file, then it is considered that it is in the file. For example, "#TokenUri" and "#Token" are treated the same. The "$initial_array" variable is taken from the vault secret store. Added to the code for ease of debugging. All keys and values are a random set of characters, close to reality. It is necessary to look for a strict one-to-one correspondence.
$pathFile = 'D:\Git\Gitlab\powershell\appsettings.json'
$array_key = #()
$array_value = #()
$initial_array = "#{#TokenUri=ovnsinv-iovi0ew-dvoiw9; #User=Vasia; #Timeout=00:00:30; #ExternalServices=gdgdfg; #Password=xvnen834n9; #ApplicationName=Tupoe; #Uri=https://gitlab.com/}" -replace '[#,{,},;]'
$array= $initial_array.Split('=').Split(' ')
for ($i = 0; $i -le $array.Count; $i++) {
if ( ($i % 2) -eq 0) {
$array[$i] | ForEach-Object { $array_key+=$_ }
}
else {
$array[$i] | ForEach-Object { $array_value+=$_ }
}
}
for ($i=0; $i -lt $array_key.Length; $i++) {
if ((Get-Content -Path $pathFile) -match $array_key[$i]) {
(Get-Content -Path $pathFile) -replace $array_key[$i], $array_value[$i] | Set-Content -Path $pathFile
}
else {
$element = $array_key[$i]
throw "Element $element is missing from the file - $pathFile"
break
}
}

Powershell to delete files from SharePoint Document libraries

I am trying to multiple files from multiple SharePoint libraries in SharePoint 2010 on Application server in the farm with the below script:
$list = Get-Content $libpath
$web = Get-Spweb $url
$lib = $web.Lists | where { $_.title -eq $libname }
foreach ($libr in $lib) {
$file = $libr.Items
foreach ( $fil in $file) {
If ($fil.Name -eq $item) {
$fil.Delete()
}
}
}
The problem is that $libr.Items is coming up empty even though the library is not empty.
$libr.Files
$libr.Files.Name
All showing up empty as well.
Please help in fixing it.
Thank you
Try the below code.
Add-PSSnapin Microsoft.SharePoint.PowerShell
$SPWeb = Get-SPWeb "Provide your web here"
$docfiles = $SPWeb.GetFolder("Provide your Document Library name here").Files
foreach ($docfile in $docfiles) {
Write-host "File Name: " $docfile.Name
$docfile.Delete();
}
Not sure what this does:
$lib = $web.Lists | where { $_.title -eq $libname }
foreach ($libr in $lib) {
$lib in this case should be a single library, why the foreach?
Can I suggest you get the library explicitly then verify that it exists:
$lib = $web.lists.TryGetList($libname)
if ($lib) {
$items = $lib.items
foreach ($item in $items) {
#Your logic here
#Do you really want to delete? Maybe use $item.Recycle()
}
}
Also if you know what you want to delete up front, look into batching as you can delete items much faster.

Powershell sorting array into multi-dimensional array with the “-like” comparison operator

I'am trying to collect my array into a multidimensional array by using the -like comparison operator for further processing.
I wrote the following array loop but i cannot replace "*kw1*" with "*$keyword[$j]*". It will break the operator validation.
$keywords = #("kw1", "kw2")
$list = #("name_kw1_000", "name_kw1_001", "name_kw1_002", "name_kw2_000", "name_kw2_001", "name_kw2_002")
$mdarr= New-Object object[][] $keywords.Length
for ($i = 0; $i -lt $list.Length; ++$i) {
for ($j = 0; $j -lt $keywords.Length; ++$j) {
if ( $list[$i] -like "*kw1*" ) {
$mdarr[$j] += $list[$i];
}
}
}
My expected output is:
$mdarr[0]
name_kw1_000
name_kw1_001
name_kw1_002
$mdarr[1]
name_kw2_000
name_kw2_001
name_kw2_002
Is this possible with the above array loop or would i have to do this completely different since the -like operator does not seem to be array friendly.
I think you mean to get output for a variable length array, using more keywords.
As montonero comments, you never test if the keyword is actually part of the item in the list of words.
Maybe this will help:
# there is no need to enclose the items with '#()'
$keywords = "kw1", "kw2"
$list = "name_kw1_000", "name_kw1_001", "name_kw1_002", "name_kw2_000", "name_kw2_001", "name_kw2_002"
# in case your keywords contain characters that have special meaning
# for regex '-match', we should escape these characters.
$keywords = $keywords | ForEach-Object { [RegEx]::Escape($_) }
# fill the object array
$mdarr= New-Object object[][] $keywords.Count
for ($i = 0; $i -lt $keywords.Count; $i++) {
foreach ($item in $list) {
if ($item -match $keywords[$i]) {
$mdarr[$i] += $item
}
}
}
# write result
for ($i = 0; $i -lt $mdarr.Count; $i++) {
Write-Host ("`$mdarr[$i]") -ForegroundColor Yellow
$mdarr[$i]
}
This will output
$mdarr[0]
name_kw1_000
name_kw1_001
name_kw1_002
$mdarr[1]
name_kw2_000
name_kw2_001
name_kw2_002

Why Isn't This Counting Correctly | PowerShell

Right now, I have a CSV file which contains 3,800+ records. This file contains a list of server names, followed by an abbreviation stating if the server is a Windows server, Linux server, etc. The file also contains comments or documentation, where each line starts with "#", stating it is a comment. What I have so far is as follows.
$file = Get-Content .\allsystems.csv
$arraysplit = #()
$arrayfinal = #()
[int]$windows = 0
foreach ($thing in $file){
if ($thing.StartsWith("#")) {
continue
}
else {
$arraysplit = $thing.Split(":")
$arrayfinal = #($arraysplit[0], $arraysplit[1])
}
}
foreach ($item in $arrayfinal){
if ($item[1] -contains 'NT'){
$windows++
}
else {
continue
}
}
$windows
The goal of this script is to count the total number of Windows servers. My issue is that the first "foreach" block works fine, but the second one results in "$Windows" being 0. I'm honestly not sure why this isn't working. Two example lines of data are as follows:
example:LNX
example2:NT
if the goal is to count the windows servers, why do you need the array?
can't you just say something like
foreach ($thing in $file)
{
if ($thing -notmatch "^#" -and $thing -match "NT") { $windows++ }
}
$arrayfinal = #($arraysplit[0], $arraysplit[1])
This replaces the array for every run.
Changing it to += gave another issue. It simply appended each individual element. I used this post's info to fix it, sort of forcing a 2d array: How to create array of arrays in powershell?.
$file = Get-Content .\allsystems.csv
$arraysplit = #()
$arrayfinal = #()
[int]$windows = 0
foreach ($thing in $file){
if ($thing.StartsWith("#")) {
continue
}
else {
$arraysplit = $thing.Split(":")
$arrayfinal += ,$arraysplit
}
}
foreach ($item in $arrayfinal){
if ($item[1] -contains 'NT'){
$windows++
}
else {
continue
}
}
$windows
1
I also changed the file around and added more instances of both NT and other random garbage. Seems it works fine.
I'd avoid making another ForEach loop for bumping count occurrences. Your $arrayfinal also rewrites everytime, so I used ArrayList.
$file = Get-Content "E:\Code\PS\myPS\2018\Jun\12\allSystems.csv"
$arrayFinal = New-Object System.Collections.ArrayList($null)
foreach ($thing in $file){
if ($thing.StartsWith("#")) {
continue
}
else {
$arraysplit = $thing -split ":"
if($arraysplit[1] -match "NT" -or $arraysplit[1] -match "Windows")
{
$arrayfinal.Add($arraysplit[1]) | Out-Null
}
}
}
Write-Host "Entries with 'NT' or 'Windows' $($arrayFinal.Count)"
I'm not sure if you want to keep 'Example', 'example2'... so I have skipped adding them to arrayfinal, assuming the goal is to count "NT" or "Windows" occurrances
The goal of this script is to count the total number of Windows servers.
I'd suggest the easy way: using cmdlets built for this.
$csv = Get-Content -Path .\file.csv |
Where-Object { -not $_.StartsWith('#') } |
ConvertFrom-Csv
#($csv.servertype).Where({ $_.Equals('NT') }).Count
# Compatibility mode:
# ($csv.servertype | Where-Object { $_.Equals('NT') }).Count
Replace servertype and 'NT' with whatever that header/value is called.