Address Variables with PowerShell and Import-CSV foreach-loop - variables

Input file:
"Server1","lanmanserver"
"Server2","lanmanserverTest"
Program
$csvFilename = "D:\Scripts\ServerMonitorConfig.csv"
$csv = Import-Csv $csvFilename -Header #("ServerName","ServiceName")
foreach ($line in $csv) {
Write-Host "ServerName=$line.ServerName ServiceName=$line.ServiceName"
}
What I want:
Server-Name=Server1 ServiceName=lanmanserver
Server-Name=Server2 ServiceName=lanmanserverT
What I'm getting:
ServerName=#{ServerName=Server1; ServiceName=lanmanserver}.ServerName
ServiceName=#{ServerName=Server1; ServiceName=lanmanserver}.ServiceN
ame ServerName=#{ServerName=Server2;
ServiceName=lanmanserverTest}.ServerName
ServiceName=#{ServerName=Server2; ServiceName=lanmanserverTest}.
ServiceName
I really don't care if the Headers come from the first row of the CSV or not, I'm flexible there.

You usually see subexpressions or format strings used to solve that:
Subexpression:
Write-Host "ServerName=$($line.ServerName) ServiceName=$($line.ServiceName)"
Format string:
Write-Host ('ServerName={0} ServiceName={1}' -f $line.ServerName,$line.ServiceName)

Related

Script to replace string of text at a end of a line

I would like to modify this script if possible:
((Get-Content -path "C:\Users\User1\OUT\Summary.txt" -Raw) -replace '</ab></cb>','</x>') | Set-Content -Path "C:\Users\User1\OUT\Summary.txt"
I would like a script that will run with Windows OS to search through one file it finds at this path:
C:\Users\User1\File\Summary.txt
And within that file, when it finds data starting with: <a><b>Data
And at the same time ending with: </ab></cb>
It would need to change the ending to: </x>
And it would need to save the file without changing the name of the file.
For instance a line showing this data:
<a><b>Data:</y> 12345678</ab></cb>
Would be changed to:
<a><b>Data:</y> 12345678</x>
The PowerShell script above will find all instances of </ab></cb> and replace it with </x>, which is not what I am hoping to accomplish.
You can use Get-Content to process the file line be line and only do the Replace when you have a Match on <a><b>. Something like this:
$InFile = ".\TestIn.txt"
$OutFile = ".\TestOut.txt"
If (Test-Path -Path $OutFile) {Remove-Item $OutFile}
Get-Content $InFile | ForEach-Object -Process {
$NewLine = $_
If ($_ -Match '<a><b>') {
$NewLine = ($_ -Replace '</ab></cb>','</x>')
}
Add-Content $OutFile $NewLine
}

How doI use Powershell to take output from a SQL query and search another file for that output

This is my first time using Powershell so please forgive my ignorance.
I have a SQL query that returns back a bunch of order numbers. I want to check another file to see if there is an existing PDF in that file with the same name as the orders numbers returned by the SQL query.
Everything in my code works up until the ForEach loop which returns nothing. Based on my google searches I think I'm pretty close but I'm not sure what I'm doing wrong. Any help would be appreciated.
I've removed the actual file name for obvious reasons, and I do know that the file is correct and other commands do access it so I know that is not my problem at the moment. I've also removed sensitive info from the SQL query.
$statement = "SELECT A, Date FROM XXXX
WHERE STAT = 1 AND Date >= trunc(sysdate)"
$con = New-Object System.Data.OracleClient.OracleConnection($connection_string)
$con.Open()
$cmd = $con.CreateCommand()
$cmd.CommandText = $statement
$result = $cmd.ExecuteReader()
$list = while ($result.Read()) { $result["A"]}
Write-Output $list​
#########Loop through the list above here to check for matching PDF
ForEach ($Order in $list){
Get-ChildItem "\\xxxxxx\" -Filter $Order -File
#########If FALSE - notify that PDF is missing
}
$con.close()
I have also tried the following code, which gets me closer and actually finds the files I'm looking for, but gives the error
" Get-ChildItem : A positional parameter cannot be found that accepts argument
CategoryInfo : InvalidArgument: (:) [Get-ChildItem], ParameterBindingException
FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand"
ForEach ($Order in $list){
if((Get-ChildItem "\\xxxxx\" + $Order)){
Write-Output
} else { Write-Host "Does not exist."}
I gather from your comment that $list is an array of order numbers.
Next, you want to check if there is a file in a folder having that name, correct?
Then I'd suggest you use Test-Path instead of Get-ChildItem:
$folderToSearch = '\\servername\sharename\folder'
foreach ($Order in $list) {
$fileToCheck = Join-Path -Path $folderToSearch -ChildPath ('{0}.pdf' -f $Order)
if (Test-Path -Path $fileToCheck -PathType Leaf) {
"File found: $fileToCheck"
}
else {
"File $fileToCheck does not exist"
}
}

PowerShell finding a file and creating a new one

The script I'm working on is producing a log file every time it runs. The problem is that when the script runs in parallel, the current log file becomes inaccessible for Out-File. This is normal because the previous script is still writing in it.
So I would like the script being able to detect, when it starts, that there is already a log file available, and if so, create a new log file name with an increased number between the brackets [<nr>].
It's very difficult to check if a file already exists, as it can have another number each time the script starts. It would be great if it could then pick up that number between the brackets and increment it with +1 for the new file name.
The code:
$Server = "UNC"
$Destination ="\\domain.net\share\target\folder 1\folder 22"
$LogFolder = "\\server\c$\my logfolder"
# Format log file name
$TempDate = (Get-Date).ToString("yyyy-MM-dd")
$TempFolderPath = $Destination -replace '\\','_'
$TempFolderPath = $TempFolderPath -replace ':',''
$TempFolderPath = $TempFolderPath -replace ' ',''
$script:LogFile = "$LogFolder\$(if($Server -ne "UNC"){"$Server - $TempFolderPath"}else{$TempFolderPath.TrimStart("__")})[0] - $TempDate.log"
$script:LogFile
# Create new log file name
$parts = $script:LogFile.Split('[]')
$script:NewLogFile = '{0}[{1}]{2}' -f $parts[0],(1 + $parts[1]),$parts[2]
$script:NewLogFile
# Desired result
# \\server\c$\my logfolder\domain.net_share_target_folder1_folder22[0] - 2014-07-30.log
# \\server\c$\my logfolder\domain.net_share_target_folder1_folder22[1] - 2014-07-30.log
#
# Usage
# "stuff" | Out-File -LiteralPath $script:LogFile -Append
As mentioned in my answer to your previous question you can auto-increment the number in the filename with something like this:
while (Test-Path -LiteralPath $script:LogFile) {
$script:LogFile = Increment-Index $script:LogFile
}
where Increment-Index implements the program logic that increments the index in the filename by one, e.g. like this:
function Increment-Index($f) {
$parts = $f.Split('[]')
'{0}[{1}]{2}' -f $parts[0],(1 + $parts[1]),$parts[2]
}
or like this:
function Increment-Index($f) {
$callback = {
$v = [int]$args[0].Groups[1].Value
$args[0] -replace $v,++$v
}
([Regex]'\[(\d+)\]').Replace($f, $callback)
}
The while loop increments the index until it produces a non-existing filename. The parameter -LiteralPath in the condition is required, because the filename contains square bracket, which would otherwise be treated as wildcard characters.

Powershell Code for List of Distinct Directories

I have a file that contains a list such as:
tables\mytable1.sql
tables\myTable2.sql
procedures\myProc1.sql
functions\myFunction1.sql
functions\myFunction2.sql
From this data (and there will always be a path, and it will always be only one level), I want to retrieve a list of distinct paths (e.g. tables\, procedures\, functions\)
To maybe make it the file that contains this data will already have been read into a list (named $fileList), so the new list ($directoryList ??) can likely derived from it.
I've found reference to the -unique parameter, but I need to look from the start of the line, up to (and including) the '\', of which there will only be one occurrence of).
Assuming you already have the data on $fileList, try this:
$directoryList = $fileList | %{ $_.split("\")[0]} | select -unique
It will do a foreach (the %{}) on the elements of your list, and then split them by the \ and get you only the first part (in your case, the folder name), after that you use select -unique to get just the distinct values.
Alternatively, you could do it like this:
$fileList | %{ $_ -replace "\\.*$","" } | select -unique
Using -replace to remove everything after the \.
Also, if for some reason you don't have the values of your textfile on $fileList already, you can do so using:
$fileList = Get-Content yourFile.txt
Your file may contain empty lines and more often than not there's an empty line on the last one so this will account for that.
It also has a slightly different regular expression to match from the end of the string that is not a \ character which will work for paths with multiple levels including your example.
If you have a text file with the following:
Z:\Path to somewhere\Files\some file 1.txt
Z:\Path to somewhere\Files\some file 2.txt
tables\mytable1.sql
tables\myTable2.sql
procedures\myProc1.sql
functions\myFunction1.sql
functions\myFunction2.sql
With this code which also shows the output after the function:
$fileListToProcess = "$([Environment]::GetFolderPath(""Desktop""))\list.txt"
Function Get-UniqueDirectoriesFromFile {
Param
(
[Parameter(Mandatory = $true, HelpMessage = 'The file where the list of files is.')]
[string]$LiteralPath
)
if (Test-Path -LiteralPath $LiteralPath -PathType Leaf) {
$fileList = [IO.File]::ReadAllLines($LiteralPath)
return $fileList | %{ $_ -replace '\\[^\\]*$', '' } | ? { $_.trim() -ne "" } | Select -Unique
}
else {
return $null
}
}
$uniqueDirs = Get-UniqueDirectoriesFromFile -file $fileListToProcess
# Display the results:
$uniqueDirs
# PS>
# Z:\Path to somewhere\Files
# tables
# procedures
# functions
$uniqueDirs.count
# PS> 4

How do I concatenate strings with variables in PowerShell?

I'm trying to build a file path in PowerShell and the string concatenation seems to be a little funky.
I have a list of folders:
c:\code\MyProj1
c:\code\MyProj2
I want to get the path to a DLL file here:
c:\code\MyProj1\bin\debug\MyProj1.dll
c:\code\MyProj2\bin\debug\MyProj2.dll
Here's what I'm trying to do:
$buildconfig = "Debug"
Get-ChildItem c:\code | % {
Write-Host $_.FullName + "\" + $buildconfig + "\" + $_ + ".dll"
}
This doesn't work. How can I fix it?
Try this
Get-ChildItem | % { Write-Host "$($_.FullName)\$buildConfig\$($_.Name).dll" }
In your code,
$build-Config is not a valid variable name.
$.FullName should be $_.FullName
$ should be $_.Name
You could use the PowerShell equivalent of String.Format - it's usually the easiest way to build up a string. Place {0}, {1}, etc. where you want the variables in the string, put a -f immediately after the string and then the list of variables separated by commas.
Get-ChildItem c:\code|%{'{0}\{1}\{2}.dll' -f $_.fullname,$buildconfig,$_.name}
(I've also taken the dash out of the $buildconfig variable name as I have seen that causes issues before too.)
Try the Join-Path cmdlet:
Get-ChildItem c:\code\*\bin\* -Filter *.dll | Foreach-Object {
Join-Path -Path $_.DirectoryName -ChildPath "$buildconfig\$($_.Name)"
}
This will get all dll files and filter ones that match a regex of your directory structure.
Get-ChildItem C:\code -Recurse -filter "*.dll" | where { $_.directory -match 'C:\\code\\myproj.\\bin\\debug'}
If you just want the path, not the object you can add | select fullname to the end like this:
Get-ChildItem C:\code -Recurse -filter "*.dll" | where { $_.directory -match 'C:\\code\\myproj.\\bin\\debug'} | select fullname