How to use custom PowerShell functions? - powershell

Question about running a custom function in Powershell.
I'm on Windows 10 and I'd like to somehow print my monorepository's directory tree structure excluding node_modules. This is not supported out of the box but requires a custom function to be defined. I found one solution on StackOverflow (https://stackoverflow.com/a/43810460/9654273), which would enable using a command like:
tree -Exclude node_modules -Ascii > tree.txt
The problem is I don't know what to do with the provided source code :D The answer says "add to your $PROFILE, for instance", so I ran notepad $PROFILE in PowerShell, pasted the code snippet there, saved it and tried running the command. It didn't work because I did something wrong. According to the StackOverflow post's comments from anand_v.singh and mklement0 I was still running some other tree command, not the one I just attempted to define.
So how do I use a custom function in PowerShell? Starting point is that source code is on StackOverflow and I don't know where to paste it. Or do you know some other, easier way to print a directory tree on Windows 10 excluding node_modules?

I had the same problem with that function. The issue is the special characters in the hashtable at line 106:
$chars = #{
interior = ('├', '+')[$ndx]
last = ('└', '\')[$ndx] #'
hline = ('─', '-')[$ndx]
vline = ('│', '|')[$ndx]
space = ' '
}
I changed the special characters to ascii as follows:
$chars = #{
interior = ('+', '+')[$ndx]
last = ('\', '\')[$ndx] #'
hline = ('-', '-')[$ndx]
vline = ('|', '|')[$ndx]
space = ' '
}
The only downside is that you do not now have the option of using special graphics characters (the Ascii switch is still there, but does nothing). Maybe someone could tell us how to embed them properly.

Related

Powershell: stripping a file name sometimes doesn't work

I have a Powershell script that is called from the command line.
script.ps1 "\\testfolder" "testinput" "xml" "xml2html.xsl" "testfile" "css"
The script uses these command line arguments:
param([string]$publish_folder, [string]$input_filename, [string]$input_ext, [string]$transformation_filename, [string]$output_filename, [string]$output_ext)
$input_filename and $output_filename may be a full path+filename, the filename only or the filename without extension.
$inputFileNameOnly = [System.IO.Path]::GetFileNameWithoutExtension($input_filename)
$inputPath=$publish_folder+"\"+$inputFileNameOnly+"."+$input_ext
$outputFileNameOnly = [System.IO.Path]::GetFileNameWithoutExtension($output_filename)
$outputPath=$publish_folder+"\"+$outputFileNameOnly+"."+$output_ext
When I run this locally, it works. Output path:
\\testfolder\testfile.css
When I run the same script in an AWS instance, it fails. $inputpath is calculated correctly, but Output path becomes:
\\testfolder\.
so both $output_filename and $output_ext are empty.
The paths are longer than \\testfolder\, but not long enough to cause trouble (about 150 characters). Total length of the arguments doesn't seem to be a problem either.
What could be causing this problem?
$outputPath="$publish_folder+"\"+
Looks like you broke your concatenation here. Double-quote before $publish_folder.
Edit:
Can also be written like this if you don't want to concatenate (+)
$outputPath="$publish_folder\$outputFileNameOnly.$output_ext"
Anything in double-quotes should be expanded correctly.
I set up your script as a function and passed those parameters.
function rename {
param(
[string]$publish_folder,
[string]$input_filename,
[string]$input_ext,
[string]$transformation_filename,
[string]$output_filename,
[string]$output_ext
)
$inputFileNameOnly = [System.IO.Path]::GetFileNameWithoutExtension($input_filename)
$inputPath = $publish_folder+"\"+$inputFileNameOnly+"."+$input_ext
$outputFileNameOnly = [System.IO.Path]::GetFileNameWithoutExtension($output_filename)
$outputPath = $publish_folder+"\"+$outputFileNameOnly+"."+$output_ext
return $outputPath
}
Output is this...
\\\\testfolder\\\\testfile.css
Try passing $publish_folder without ending backslash
Edit: Sorry about formatting. Need some forum practice. =)
With some more testing, we found the cause of the problem.
$outputFileNameOnly = [System.IO.Path]::GetFileNameWithoutExtension($output_filename)
GetFileNameWithoutExtension fails (in the AWS instance) when $output_filename does not contain an extension. On my local machine this worked correctly.
So we added an extension to the command line argument and the script works correctly.

Windows Powershell- Adding to a variable in a command call

I am new to Powershell and Stack Overflow, so sorry if this an obvious question. I have searched and searched and have not found any similar questions or answers. I am trying to call a command on Powershell and changing the file name by one. Here is the line giving me trouble:
fconv -rmsd ${line}_O[int]($modeO+1).mol2 --s=${line}_A$modeA.mol2
This program takes a line of code in the format
fconv -rmsd FILE_NAME.mol2 --s=FILE_NAME.mol2
and gives a result. My problem is adding 1 to $modeO. $modeO is a number that is pulled from a file and converted to an int by using
$modeO = file.txt | Select -Index 0
[int]$modeO = [convert]::ToInt32($ModeO.Trim(), 10)
Now, whenever I try this command it says "could not open 5157_O6+1.mol2" when modeO is 6. I want it to use the file O7, but the +1 is not adding properly. I have tried separating it with parentheses, curly braces, and putting [int] in front of ($modeO+1). Is there a way to add to a variable like this while using it? Any help is appreciated, thank you!

How convert multiple RTF-file to TXT-file

Looking here:
Is it possible to change an .rtf file to .txt file using some sort of batch script on Windows?
I have saw which possible use POWERSHELL for to do it. Was present a full example for to do it but link don't work.
Who can tell me as i can to solve it? Thanks.
You can use .NET to do this in powershell very easily by implementing the System.Windows.Forms.RichTextBox control, loading the richtextfile into it, then pulling the text version out. This is by far the easiest and quickest way I have found to do this.
My function for doing exactly this is here: https://github.com/Asnivor/PowerShell-Misc-Functions/blob/master/translate-rtf-to-txt.ps1
To explain this a little more basically:
$rtfFile = [System.Io.FileInfo]"path/to/some/rtf/file"
$txtFile = "path/to/the/destination/txt/file"
# Load *.rtf file into a hidden .NET RichTextBox
$rtBox = New-Object System.Windows.Forms.RichTextBox
$rtfText = [System.IO.File]::ReadAllText($rtfFile);
$rtBox.Rtf = $rtfText
# Get plain text version
$plainText = $rtBox.Text;
# Write the plain text out to the destination file
[System.IO.File]::WriteAllText($txtFile, $plainText)

PowerShell 3 ExpandString loses text

I'm finding that in PowerShell 3, ExpandString is truncating my template string and only giving the very beginning of it. This worked in PowerShell 2 without a hitch, so I'm not sure what's going wrong.
The goal is to insert the value of $theSetting into the template string. Note that I use a regex to escape quotes and graves so that PowerShell doesn't try to expand them, and that appears to be working fine.
PS > $theSetting = 'x'
PS > $template = '<?xml version="1.0" encoding="utf-8" ?><AppSettings><Setting value="${theSetting}"/></AppSettings>'
PS > $template = $template -replace "('|`"|``)", '`$1'
PS > $template
<?xml version=`"1.0`" encoding=`"utf-8`" ?><AppSettings><Setting value=`"${theSetting}`"/></AppSettings>
PS > $ExecutionContext.InvokeCommand.ExpandString($template)
<?xml version="
For some reason, it's cutting it off after the first double quote. I appreciate any help in identifying what changed between PowerShell 2 and 3.
As you might guess given the template text, I'm actually loading the template from a file and writing the contents back out, and this is being used for configuration files that are far more variable and complex than the sample template seen here. So something simple like a regex instead isn't really an option.
For the benefit of future readers, don't do this. Use a real templating engine (e.g., Mustache).
Powershell 3 changed the way it parses strings to where you no longer need to change the " to `". I'm not quite sure why it evaluates it as the end of a string though.
Like Keith said, if you remove the replace code you have you will be fine. You can also detect to see if you are running on a lower powershell version and do the replacement like this:
if ($PSVersionTable.PSVersion.Major -lt 3) { $var = $var -replace '"','`"' }
Hope this helps

Why is my text file incomplete after using StreamWriter object?

I wrote a small program which generates big text files. I found using a StreamWriter is much, much faster than other methods I know. But the end of each text file is missing.
I reduced the program to a very simple snippet to spot the problem, but I'm still unable to understand how to solve it.
#$stream = [System.IO.StreamWriter] "test.txt"
# also tested with $stream = New-Object System.IO.StreamWriter("test.txt")
$i = 1
while($i -le 500) {
$stream.WriteLine("$i xxxxxx")
$i++
}
$stream.flush # flushing don't change anything
$stream.close # also tested with $stream.dispose
exit 0
Problem 1:
The end of the file is missing. Depending of line length, the last line is around 495, generaly cut in the middle of the line.
Problem 2:
When the program is finished, the text file is still locked (we can read it, but not delete/rename). We have to exit from PowerShell to gain full access to the file.
Tested on Windows 2003 and Windows 2008 with exact same result.
EDIT
dugas found the problem: I forgotten some parenthesis. Which solve the problem show with my code snippet.
But my original program have the parenthesis. So I mark this question as solved, and will open a new one when I'll found a better snippet for this specific problem.
EDIT 2
Got it. I had a hidden exception. Many thanks !
You are missing parenthesis when calling the StreamWriter's methods:
Change:
$stream.close
to
$stream.Close()
You may also want to wrap your StreamWriter in a try/finally and call Dispose on it in the finally:
try
{
$stream = [System.IO.StreamWriter] "C:\Users\168357\Documents\test2.txt"
$stream.WriteLine("xxxxxx")
}
finally
{
if ($stream -ne $NULL)
{
$stream.Dispose()
}
}