How to know specific string exist or not in PowerShell? - azure

I want to verify the database for the given script in CI.
I want to check specific string exists or not in the given file.
Below is the content of my file
USE [SampleDB]
I am reading the content of my file and checking [SampleDB] string exists or not in the file.
I have tried the below things.
If(Get-Content -path D:/Document/admin.sql | Select-String -Pattern "[SampleDB]")
{
# Right Database exist
} else {
# Right Database does not exist
}
How can I verify the right database name after the USE string?

Select-String uses regular expressions to perform string searches, and the construct [...] has a special meaning in that context - namely, it means "match any one of these characters", not quite what you're expecting.
To search for the word [SampleDB] verbatim you either have to escape it correctly:
# escape your search term!
$searchTerm = [regex]::Escape('[SampleDB]')
if(Get-Content -path D:/Document/admin.sql | Select-String -Pattern $searchTerm) {
# Right Database exist
} else {
# Right Database does not exist
}
... or you can request Select-String perform a non-regex match with the -SimpleMatch switch:
if(Get-Content -path D:/Document/admin.sql | Select-String -Pattern "[SampleDB]" -SimpleMatch) {
# Right Database exist
} else {
# Right Database does not exist
}

Related

PowerShell Regex get multiple substrings between 2 strings and write them to files with sequence numbers

Old thread
My question regards:
function GetStringBetweenTwoStrings($firstString, $secondString, $importPath){
#Get content from file
$file = Get-Content $importPath
#Regex pattern to compare two strings
$pattern = "$firstString(.*?)$secondString"
#Perform the opperation
$result = [regex]::Match($file,$pattern).Groups[1].Value
#Return result
return $result
}
GetStringBetweenTwoStrings -firstString "Lorem" -secondString "is" -importPath "C:\Temp\test.txt"
This is nice for only one -firstString and -secondString, but how to use this function to chronologically write multiple same strings in numbered TXT?
txt - file(with more sections of text):
Lorem
....
is
--> write to 001.txt
Lorem
....
is
--> write to 002.txt
and so forth....
And the structure of the section is preserved and is not in one line.
I hope someone can tell me that. Thanks.
The function you quote has several limitations (I've left feedback on the original answer), most notably only ever reporting one match.
Assuming an improved function named Select-StringBetween (see source code below), you can solve your problem as follows:
$index = #{ value = 0 }
Get-ChildItem C:\Temp\test.txt |
Select-StringBetween -Pattern 'Lorem', 'is' -Inclusive |
Set-Content -LiteralPath { '{0:000}.txt' -f ++$index.Value }
Select-StringBetween source code:
Note: The syntax is in part patterned after Select-String. After defining the function, run Select-StringBetween -? to see its syntax; the parameter names are hopefully self-explanatory.
function Select-StringBetween {
[CmdletBinding(DefaultParameterSetName='String')]
param(
[Parameter(Mandatory, Position=0)]
[ValidateCount(2, 2)]
[string[]] $Patterns,
[Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName='File')]
[Alias('PSPath')]
[string] $LiteralPath,
[Parameter(Mandatory, ValueFromPipeline, ParameterSetName='String')]
[string] $InputObject,
[switch] $Inclusive,
[switch] $SimpleMatch,
[switch] $Trim
)
process {
if ($LiteralPath) {
$InputObject = Get-Content -ErrorAction Stop -Raw -LiteralPath $LiteralPath
}
if ($Inclusive) {
$regex = '(?s)(?:{0}).*?(?:{1})' -f
($Patterns[0], [regex]::Escape($Patterns[0]))[$SimpleMatch.IsPresent],
($Patterns[1], [regex]::Escape($Patterns[1]))[$SimpleMatch.IsPresent]
}
else {
$regex = '(?s)(?<={0}).*?(?={1})' -f
($Patterns[0], [regex]::Escape($Patterns[0]))[$SimpleMatch.IsPresent],
($Patterns[1], [regex]::Escape($Patterns[1]))[$SimpleMatch.IsPresent]
}
if ($Trim) {
[regex]::Matches(
$InputObject,
$regex
).Value.Trim()
}
else {
[regex]::Matches(
$InputObject,
$regex
).Value
}
}
}
Note that there's also a pending feature request on GitHub to add this functionality directly to Select-String - see GitHub issue #15136

Version strings to "System.Version" too long (or short) in PowerShell

How can I force conversion to type System.Version in PowerShell, or more likely, better understand why I cannot arbitrarily assign number strings type System.Version?
We ingest some software updates in folders whose titles include version numbers. In trying to get reports on what the latest versions ingested are, I have been doing the following quick and dirty:
ForEach ($Folder in $(Get-ChildItem -Path $SoftwareDirectory -Directory))
{
$CurrentVersion = $Folder -Replace "[^0-9.]"
If ($CurrentVersion -ne $null)
{
If ([System.Version]$CurrentVersion -gt [System.Version]$MaxVersion)
{
$MaxVersion = $CurrentVersion
$MaxFolder = $Folder
}
}
}
This would be fed directory titles like the following,
foo-tools-1.12.file
bar-static-3.4.0.file
Most of the time, this is acceptable. However, when encountering some oddballs with longer numbers, like the following,
applet-4u331r364.file
In which case, System.Version refuses the resulting string as being too long.
Cannot convert value "4331364" to type "System.Version". Error: "Version string portion was too short or too long."
You need to ensure that your version strings have at least two components in order for a cast to [version] to succeed:
(
#(
'oo-tools-1.12.file'
'bar-static-3.4.0.file'
'applet-4u331r364.file'
) -replace '[^0-9.]'
).TrimEnd('.') -replace '^[^.]+$', '$&.0' | ForEach-Object { [version] $_ }
The above transforms 'applet-4u331r364.file' into '4331364.0', which works when cast to [version].
Note that you can avoid the need for .TrimEnd('.') if you exclude the filename extension to begin with: $Folder.BaseName -replace '[^0-9.]'
-replace '^[^.]+$', '$&.0' matches only strings that contain no . chars., in full, i.e. only those that don't already have at least two components; replacement expression $&.0 appends literal .0 to the matched string ($&).
Output (via Format-Table -AutoSize):
Major Minor Build Revision
----- ----- ----- --------
1 12 -1 -1
3 4 0 -1
4331364 0 -1 -1

Check content of file and add string if not exists

I want to do the following:
I need to check the content of a (text) file. If a defined string is not there, it has to be inserted on a specific position.
I.e.:
My textfile is a configuration file with different sections, example:
[default]
name=bob
alias=alice
foo=bar
example=value
[conf]
name=value
etc=pp
I want to check if the string “foo=bar” and “example=value” exists in this file. If not, it has to get inserted, but I can't just append the new lines, since they have to be in the certain (here [default]) section and not to the end of the file. The position within the section doesn’t matter.
I tried with the following PowerShell script, which actually just looks for a definitely existing string and adds the new lines after it. Therefore I can make sure that the new lines get inserted in the right section, but I can't make sure that they won't be doubled, since my script doesn't check if they already exist.
$InputFile = "C:\Program Files (x86)\Path\to\file.ini"
$find = [regex]::Escape("alias=alice")
$addcontent1 = "foo=bar"
$addcontent2 = " example=value `n"
$InputFileData = Get-Content $InputFile
$matchedLineNumber = $InputFileData |
Where-Object{$_ -match $find} |
Select-Object -Expand ReadCount
$InputFileData | ForEach-Object{
$_
if ($_.ReadCount -eq ($matchedLineNumber)) {
$addcontent1
$addcontent2
}
} | Set-Content $InputFile
As mentioned by Bill_Stewart, Ansgar Wiechers and LotPings there are multiple modules to work with .ini files available in the web.
Let's take this one for example. Once you download it and import you can see how it imports your file (I removed foo=bar to demonstrate):
PS C:\SO\51291727> $content = Get-IniContent .\file.ini
PS C:\SO\51291727> $content
Name Value
---- -----
default {name, alias, example}
conf {name, etc}
From here what you want to do is pretty simple - check if key exists and if not - add:
if ($content.default.foo -ne 'bar') {
$content.default.foo='bar'
}
Verify that the value has been inserted:
PS C:\SO\51291727> $content.default
Name Value
---- -----
name bob
alias alice
example value
foo bar
And export:
$content | Out-IniFile .\out.ini

Powershell Passing Variable to Function

I don't understand what is going on...
In the VerifyEmailSettings function, the $AdminEmailAddress is one of many parameters i can pass to the ps command i am using.
I want to be able to pass the paramater name, and value to other functions like below. However, when i pass this along, i get some odd results. As you can see in the results, trying to print the $SettingName in the VerifyEmailSettings function echos AdminEmailAddress admin#superuser.com Verified, Same instead of what i want... AdminEmailAddress Verified, Same The "admin#superuser.com is mixed in there somehow. Same happens with the $SetName in the SetEmailSettings functions.
Thanks in advance!!
Write-Host "Starting Script"
#Assigning Variables
$AdminEmailAddress = "admin#superuser.com"
$SmtpServer = "exchange.local"
$FromEmailAddress = "fsrm#omg.com"
If (GetInstallStatus){
Write-Host "FSRM Installed, Skipping Install"
Write-Host "Checking Email Settings"
VerifyEmailSettings([string]"AdminEmailAddress",[string]$AdminEmailAddress)
} else {
Write-Host "FSRM Not Installed, Installing"
Install-WindowsFeature –Name FS-Resource-Manager –IncludeManagementTools
If (GetInstallStatus){
Write-Host "FSRM Installed"
} else {
Write-Host "FSRM Error on Install, Halting"
#halt here
}
}
function GetInstallStatus {
$status = (Get-WindowsFeature -Name FS-Resource-Manager | ft Installed -autosize -hidetableheaders | out-string).trim();
return $status
}
function VerifyEmailSettings([string]$SettingName, [string]$SettingData) {
$Verify = (Get-FsrmSetting | Select-Object $SettingName | FT -autosize -hidetableheaders | Out-String).Trim()
If ($Verify -eq $SettingData) {
Write-Host $SettingName "Verified, Same"
SetEmailSettings([string]$SettingName, [string]$SettingData)
} Else {
Write-Host $SettingName "Wrong, Updating"
SetEmailSettings([string]$SettingName, [string]$SettingData)
}
}
function SetEmailSettings([string]$SetName, [string]$SetData) {
$SetName
#Set-FsrmSetting $SetName $SetData
}
Here is the results i get:
Starting Script
FSRM Installed, Skipping Install
Checking Email Settings
AdminEmailAddress admin#superuser.com Verified, Same
AdminEmailAddress admin#superuser.com
Do not call PowerShell functions with parentheses and commas
VerifyEmailSettings([string]"AdminEmailAddress",[string]$AdminEmailAddress)
What you're actually doing here is passing an array containing both values as the first argument and nothing for the second argument. That should be written like this:
VerifyEmailSettings "AdminEmailAddress" $AdminEmailAddress
Or
VerifyEmailSettings -SettingName "AdminEmailAddress" -SettingData $AdminEmailAddress
(there is no need to cast your strings as [string])
Use Strict Mode
What you've done is a common error in PowerShell, made more common by the fact that you do use parentheses and commas when calling methods on .Net objects. I still do this once in a while after years of using PowerShell.
You can set strict mode which actually catches this for you and warns you about it:
Set-StrictMode -Version 2.0

Know the from a fullname string if path is a folder or a file?

Sorry for the title. I'll try to explain better.
Let's suppose that I run this command in order to get all paths of a directory and I want to redirect them to a text file.
gci e:\mytree -r | % {$_.fullname} | out-file e:\folderstructure.txt
Now I need to recreate this nested structure using new-item cmdlet.
Let's suppose now that I run this command:
gc e:\folderstructure.txt | % {
[system.io.fileinfo]$info = $_
write-host $info $info.extension
}
that produces this output:
E:\mytree\folder1
E:\mytree\folder2
E:\mytree\folder3
E:\mytree\file1.txt .txt
E:\mytree\file12.txt .txt
E:\mytree\folder1\folder.with.dots .dots
E:\mytree\folder1\folder.with.dots\file inside folder with dots.txt .txt
E:\mytree\folder3\file4.doc .doc
As you can see folder.with.dots is a folder but "it's seen" as a file (it gives me .dots extension) because it contains dots within name. If I don't know all possible extensions of my files is there any property that can tell me if an object iscontainer or not so that I can use new-item with the right switch file or directory to create it?
I hope you have understood my problem despite my English. Thanks in advance.
edit. UPDATE after JPBlanc answer
Thank you very much. :)
I was trying in this way:
gc e:\folderstructure.txt | % {
[system.io.directoryinfo]$info = $_
if ($info.psiscontainer) {
write-host "$info is a folder" }
else {
write-host "$info is a file" }
}
and the output was:
E:\mytree\folder1 is a file
E:\mytree\folder2 is a file
E:\mytree\folder3 is a file
E:\mytree\file1.txt is a file
E:\mytree\file12.txt is a file
E:\mytree\folder1\folder.with.dots is a file
E:\mytree\folder1\folder.with.dots\file inside folder with dots.txt is a file
E:\mytree\folder3\file4.doc is a file
Following your advice:
gc e:\folderstructure.txt | % {
[system.io.directoryinfo]$info = $_
if ((get-item $info).psiscontainer) {
write-host "$info is a folder" }
else {
write-host "$info is a file" }
}
E:\mytree\folder1 is a folder
E:\mytree\folder2 is a folder
E:\mytree\folder3 is a folder
E:\mytree\file1.txt is a file
E:\mytree\file12.txt is a file
E:\mytree\folder1\folder.with.dots is a folder
E:\mytree\folder1\folder.with.dots\file inside folder with dots.txt is a file
E:\mytree\folder3\file4.doc is a file
everything works fine. Now I can achieve my goal. Thanks again.
LAST EDIT.
I had another idea. I decided to check if an object is a file or a folder before creating txt file. After some difficulties (for example I've soon discovered that I can't redirect format-table that I was using to hide table headers to export-csv
http://blogs.msdn.com/b/powershell/archive/2007/03/07/why-can-t-i-pipe-format-table-to-export-csv-and-get-something-useful.aspx )
I came up with this solution:
gci e:\mytree -r |
select fullname,#{n='folder';e={ switch ($_.psiscontainer) {
true {1}
false {0}
}
}
} | % {($_.fullname,$_.folder) -join ","} | out-file e:\structure.txt
that gets me this output:
E:\mytree\folder1,1
E:\mytree\folder2,1
E:\mytree\folder3,1
E:\mytree\file1.txt,0
E:\mytree\file12.txt,0
E:\mytree\folder1\folder.with.dots,1
E:\mytree\folder1\folder.with.dots\file inside folder with dots.txt,0
E:\mytree\folder3\file4.doc,0
So I can easily split two parameters and use new-item cmdlet accordingly to object type.
Both FileInfo type an DirectoryInfo type has got a property PSIsContainer, that allow you to see if the object is a directory or not.
PS C:\temp> (Get-Item 'Hello world.exe').PSIsContainer
False
PS C:\temp> (Get-Item 'c:\temp').PSIsContainer
True
I modified your code slightly to this:
gc c:\scripts\files.txt | % {
$item = Get-item $_
Write-Host $item.fullName $item.PSIscontainer
}
Now, my output looks like this:
C:\Scripts\mytree\folder1 True
C:\Scripts\mytree\folder2 True
C:\Scripts\mytree\file1.txt False
C:\Scripts\mytree\file2.txt False
C:\Scripts\mytree\folder.with.dots True
C:\Scripts\mytree\folder.with.dots\file inside folder with dots.txt False

Resources