Load file file with PowerShell? - windows

I would like to load a file, contains vars' statements.
For example, VLANS.conf will contain $VLANS = "VLAN1500", "VLAN877"
How do I load it into powershell?

Read the file content and use the Invoke-Expression cmdlet to evaluate each line as an expression:
PS > Get-Content .\VLANS.conf | Foreach-Object {Invoke-Expression $_}
PS >$VLANS
VLAN1500
VLAN877

Alternative is to have a VLANS.ps1 or VLANS.conf.ps1 or something and "dot source the file"?
. .\VLANS.ps1
You will have the advantage of having here-strings, script blocks ( and of course anything you can have in a powershell script)

Related

Bash script to copy files in PowerShell

Is it possible to copy files using bash script (.sh) on powershell?
Tried using cp and copy, but got command not found error. However, if use cp or copy in the powershell command line, it does work.
I tried
Copy-Item -path "$file_path" -Destination "C:\destination\"
where $file_path is a variable with the source file This resulted in syntax errors-
Unexpected EOF while looking for matching ' " '
syntax error: unexpected end of file
The exact same copy-item command works when executed in powershell command line.
You don't need double quotes for simple string text or a simple variable.
Copy-Item -path $file_path -Destination 'C:\destination'
Double quotes are for variable expansion use cases where it is needed and in some formatting use cases. For example, combining a variable with something else, so say a file path.
Get-ChildItem -Path 'D:\Temp' |
ForEach {
$PSItem
$PSitem.BaseName
'Processing ' + $PSItem.FullName
"Processing $($PSItem.FullName)"
} |
Select -First 4 |
Format-Table -AutoSize
# Results
<#
Directory: D:\Temp
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 06-May-20 20:30 AddressFiles
AddressFiles
Processing D:\Temp\AddressFiles
Processing D:\Temp\AddressFiles
#>
So, if I took your sample and refactor a bit so you can see what I mean:
$File_path = 'D:\Temp'
Get-ChildItem -Path $File_path -File |
Select -First 4 |
ForEach {
Copy-Item -Path $PSItem.FullName -Destination 'D:\Temp\est' -WhatIf
}
# Results
<#
What if: Performing the operation "Copy File" on target "Item: D:\Temp\(MSINFO32) command-line tool switches.pdf Destination: D:\Temp\est\(MSINFO32) comm
and-line tool switches.pdf".
What if: Performing the operation "Copy File" on target "Item: D:\Temp\23694d1213305764-revision-number-in-excel-book1.xls Destination: D:\Temp\est\23694
d1213305764-revision-number-in-excel-book1.xls".
What if: Performing the operation "Copy File" on target "Item: D:\Temp\5 Free Software You'll Wish You Knew Earlier! 2019 - YouTube.url Destination: D:\T
emp\est\5 Free Software You'll Wish You Knew Earlier! 2019 - YouTube.url".
What if: Performing the operation "Copy File" on target "Item: D:\Temp\abc.bat Destination: D:\Temp\est\abc.bat".
#>
Yet again, as [David C. Rankin], unless your environment is properly configured, you can only run PowerShell commands in the PowerShell consolehost, ISE or VSCode.
You can run external executables in PowerShell, but you must call it properly, especially if you are using the PowerShell ISE.
• PowerShell: Running Executables
Table of Contents
Direct - Using the environment path or local folder
Invoke-Expression (IEX)
Invoke-Command (ICM)
Invoke-Item (II)
The Call Operator &
cmd /c - Using the old cmd shell
Start-Process (start/saps)
[Diagnostics.Process] Start()
WMI Win32_Process Create() Method
Stop-Parsing Symbol --%

How to show file and folder names along with terminal icons without showing current directory?

I want to remove the space/ area taken up in showing the
Directory: C:\Users\varun\Desktop\Projects\advanced-react-patterns-v2
when I run the command:
Get-ChildItem | Format-Wide
Additional details:
Using Windows Terminal & Powershell
Font used in the screenshot: TerminessTTF NF
Used Terminal-Icons
Note: The command
Get-ChildItem -Name
failed to show the terminal icons which kind of my main goal here.
When you are using a Format-* command you are using the default formatting output for the File and Directory objects, which groups files by directory - hence the directory name at the top.
If you wanted to by pass this, you would have to write your own format.ps1xml file and then add the formatting to your output.
$files = Get-ChildItem
foreach ($file in $files) {
$file.PSObject.TypeNames.Insert(0,'Custom.Output.Type')
$file
}
Small sample of XML for the specified Typename, customise as you wish.
<View>
<Name>CustomFileFormatting</Name>
<ViewSelectedBy>
<TypeName>Custom.Output.Type</TypeName>
</ViewSelectedBy>
<TableControl>
<AutoSize />
<TableHeaders>
<TableColumnHeader>
<Label>FullName</Label>
<Alignment>Left</Alignment>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>FSObject</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>

How to get the name of a directory by regex?

I need to get the path or name of a directory, the things I know about it:
- the folder the directory is on
- its name follows a given regex
How can I accomplish this?
Working on Jenkins pipeline (groovy)
You can apply the pwd pipeline step to return the current directory as String and fetch the name from it by using regex groups.
See the following example to extract values from regex using groovy: https://gist.github.com/EwanDawson/2407215
I ended up assigning the result of powershell to the variable, I did this by telling the powershell step that it has a stdout return like:
def folder = powershell (returnStdout: true, script: """
Get-ChildItem -directory | Select-String -pattern '<pattern>'
""")
That combined with pwd() gives me the full path, although you can also get full path using a pipeline in the command, something like Get-ChildItem -directory | Select-Object Fullname | Select-String -pattern '<pattern>'

Batch file no longer executes after running find/replace Powershell script on it

Yesterday I ran the following script on some batch files on our server to replace an individual's email address as she is no longer with the company. When examining the text it worked perfectly and the log file wrote correctly as well. However, now the batch file no longer executes when I double click on it. I see a quick flash of the console window but there does not appear to be any text in it. Adding PAUSE statements is not helpful as it does not seem to execute any of the text in the file.
I copied and pasted the text to a new batch file and it works fine. I noticed that the powershell-edited file is 6KB and the new copied-and-pasted file is 3KB so clearly the script has done something unexpected to the file. Copying and pasting each file obviously defeats the purpose of using a script to batch process things. Any ideas where I'm going wrong?
I've been running the script from my development machine and I have full administrator permissions to everything on our network.
If it matters we are running Windows Server 2008 R2 Enterprise on the server.
# Finds string in batch files recursively and replaces text with other text
#
#get command line arguments
param (
[string]$Text = $( Read-Host "Input the text to search for"),
[string]$Replacement = $( Read-Host "Input the replacement text")
)
$Today=get-date -format yyyymmdd
$Results = "{server name}\c$\Batch Jobs\Find Text In Batch Jobs\ReplaceTextInBatchJobs-" + $Text + "-" + $Today + ".txt"
$Path = "{server name}\c$\Batch Jobs"
# get all the files in $Path that end in ".bat".
Get-ChildItem $Path -Filter "*.bat" -Recurse |
Where-Object { $_.Attributes -ne "Directory"} |
ForEach-Object {
#Find whether there is a matching string
If (Get-Content $_.FullName | Select-String -Pattern $Text) {
#Replace the text in this file
(Get-Content $_.FullName) | Foreach-Object {$_ -replace $Text, $Replacement} |
Out-File $_.FullName #write the new results back to the file
#write the file name to a log file
$_.FullName >> $Results
}
}
Out-File defaults to Unicode encoding (which is why the file doubles in size; each character is 16 bits). You can either use Out-File -Encoding ASCII or Set-Content which defaults to ASCII.

How can I source variables from a .bat file into a PowerShell script?

I'm replacing parts of a .bat script with PowerShell. Configuration for the batch files is done via files that set appropriate environment variables. I'm looking for a way to load those variable values into the .ps1 script, without modifying the .bat files (as they are also used in other places.
An example .bat looks as follows:
set VAR_ONE=some_value
set VAR_TWO=/other-value
In a batch script, I'd just CALL the configuration file and the variables would be available. I've tried both dot-sourcing (. filename.bat) and calling (& filename.bat) the configuration files from PowerShell, neither of those makes the variables visible. Tried accessing them with both with $VAR_ONE and $env:VAR_ONE syntax.
What would be a good way to load such configuration file without modifying it's format on disk?
If you are using the PowerShell Community Extensions, it has a Invoke-BatchFile that does this. I use with the Visual Studio vcvarsall.bat file to configure my PowerShell session to use the Visual Studio tools.
I'd parse them (just skip all lines that don't start with set and split them with first = character. You can do it from o small C# cmdlet or directly with a small PowerShell script:
CMD /c "batchFile.bat && set" | .{process{
if ($_ -match '^([^=]+)=(.*)') {
Set-Variable $matches[1] $matches[2]
}
}}
I have this code and I'm sure it comes from somewhere but credits have been lost, I suppose it comes from Power Shell Community Extensions for an Invoke-Batch script.
The preferred option would be to change the configuration to a .ps1 file and change the variable definitions to PowerShell syntax:
$VAR_ONE = 'some_value'
$VAR_TWO = '/other-value'
Then you'll be able to dot-source the file:
. filename.ps1
If you want to stick with the format you currently have, you'll have to parse the values, e.g. like this:
Select-String '^set ([^=]*)=(.*)' .\filename.bat | ForEach-Object {
Set-Variable $_.Matches.Groups[1].Value $_.Matches.Groups[2].Value
}
Note: The above won't work in PowerShell versions prior to v3. A v2-compatible version would look like this:
Select-String '^set ([^=]*)=(.*)' .\filename.bat | ForEach-Object {
$_.Matches
} | ForEach-Object {
Set-Variable $_.Groups[1].Value $_.Groups[2].Value
}
You can do that via a Batch file that first call the configuration file and then execute the PowerShell script.
Assuming the .bat is called test.bat, define testps.ps1:
$lines = cat "test.bat"
$output = #{};
foreach ($line in $lines) {
$bits = $line.Split("=");
$name = $bits[0].Split(" ")[1];
$val = $bits[1];
$output[$name] = $val
}
return $output
Then the result is something like:
C:\temp> .\testps.ps1
Name Value
---- -----
VAR_TWO /other-value
VAR_ONE some_value
C:\temp> $x = .\testps.ps1
C:\temp> $x
Name Value
---- -----
VAR_TWO /other-value
VAR_ONE some_value
C:\temp> $x["VAR_ONE"]
some_value
There is probably a nicer way of doing the splits (will edit if I find it)

Resources