Use a variable in a command - powershell

This is part of the PowerShell script I am working on:
Write-Host $configJson.myVal
(Get-Content .\config.js) -replace "S=''", "S='$configJson.myVal';" | Set-Content .\out.js
The Write-Host part correctly displays the value in $configJson.myVal.
But when I run the second statement, the value that is put in the file is: System.Collections.Generic.Dictionary'2[System.String,System.Object].deployedBaseUrl
How can I change the second command so that the value that is output on the Write-Host line is also put into the file for my replace command?

I would use a format string:
Write-Host $configJson.myVal
(Get-Content .\config.js) -replace "S=''", ("S='{0}';" -f $configJson.myVal) | Set-Content .\out.js

Related

Save powershell script after entering details for read-host

Example:
$nameofpath = read-host "enter path"
get-services | export-csv "$nameofpath"
I want a script so after entering a path such as c:\files\test.txt in the example above, it will save a script with:
get-services | export-csv "c:\files\test.txt"
... so I could go to that file click it and it will run.
At the moment I have an draft script like this but if I know how to do the first example I should hopefully be able to do the same for that
You'd either need to change the script that you're running, or query some other text file. If there is anything in the text file, use that; otherwise, prompt for the value. Here's an example of how you could change the script you're running using the $PSCommandPath (it's an automatic variable that contains the full path and file name of the script that is being run) variable:
$Foo = $null
#If $Foo is $null prompt for value then write that value to the script.
if($Foo -eq $null){
$Foo = Read-Host "Foo"
#Need to becarful not to match this line
$NewScript = Get-Content $PSCommandPath | ForEach-Object {$_ -replace '^\$Foo = \$null$',"`$Foo = '$Foo'"}
$NewScript | Out-File $PSCommandPath -Force
}
Write-Host "Foo $Foo"
Hope this helps.
This looks amateur but works as expected
$path = [Microsoft.VisualBasic.Interaction]::InputBox("Enter path")
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') | Out-Null
get-service | export-csv -path $path\services.csv # original command
$Command="get-service | export-csv -path $path\services.csv" # same copy here to save
$command |Out-File "D:\exportservice.ps1" # where you want the file to be saved to run later

Prevent trailing newline in PowerShell Out-File command

How do I prevent PowerShell's Out-File command from appending a newline after the text it outputs?
For example, running the following command produces a file with contents "TestTest\r\n" rather than just "TestTest".
"TestTest" | Out-File -encoding ascii test.txt
In PowerShell 5.0+, you would use:
"TestTest" | Out-File -encoding ascii test.txt -NoNewline
But in earlier versions you simply can't with that cmdlet.
Try this:
[System.IO.File]::WriteAllText($FilePath,"TestTest",[System.Text.Encoding]::ASCII)
To complement briantist's helpful answer re -NoNewline:
The following applies not just to Out-File, but analogously to Set-Content / Add-Content as well; as stated, -NoNewline requires PSv5+.
Note that -NoNewline means that with multiple objects to output, it is not just a trailing newline (line break) that is suppressed, but any newlines.
In other words: The string representations of the input objects are directly concatenated, without a separator (terminator).
Therefore, the following commands result in the same file contents (TestTest without a trailing newline):
# Single input string
"TestTest" | Out-File -encoding ascii test.txt -NoNewline
# Equivalent command: 2-element array of strings that are directly concatenated.
"Test", "Test" | Out-File -encoding ascii test.txt -NoNewline
In order to place newlines only between, but not also after the output objects, you must join the objects with newlines explicitly:
"Test", "Test" -join [Environment]::NewLine |
Out-File -encoding ascii test.txt -NoNewline
[Environment]::NewLine is the platform-appropriate newline sequence (CRLF on Windows, LF on Unix-like platforms); you can also produce either sequence explicitly, if needed, with "`r`n" and "`n"
Caveat:
The above -join solution implicitly converts the input objects to strings, if they aren't already and does so by calling the .NET .ToString() method on each object. This often yields a different representation than the one that Out-File would directly create, because Out-File uses PowerShell's default output formatter; for instance, compare the outputs of (Get-Date).ToString() and just Get-Date.
If your input comprises only strings and/or non-strings whose .ToString() representation is satisfactory, the above solution works, but note that it is then generally preferable to use the Set-Content cmdlet, which applies the same stringification implicitly.
For a complete discussion of the differences between Out-File and Set-Content, see this answer of mine.
If your input has non-strings that do you want to be formatted as they would print to the console, there is actually no simple solution: while you can use Out-String to create per-object string representations with the default formatter, Out-String's lack of -NoNewline (as of v5.1; this GitHub issue suggests introducing it) would invariably yield trailing newlines.
To complement briantist's and mklement0's helpful answers re -NoNewline:
I created this little function to replace the -NoNewLine parameter of Out-File in previous versions of powershell.
Note: In my case it was for a .csv file with 7 lines (Days of the week and some more values)
## Receive the value we want to add and "yes" or "no" depending on whether we want to
put the value on a new line or not.
function AddValueToLogFile ($value, $NewLine) {
## If the log file exists:
if (Test-path $Config.LogPath) {
## And we don't want to add a new line, the value is concatenated at the end.
if ($NewLine -eq "no") {
$file = Get-Content -Path $Config.LogPath
## If the file has more than one line
if ($file -is [array]) {
$file[-1]+= ";" + $value
}
## if the file only has one line
else {
$file += ";" + $value
}
$file | Out-File -FilePath $Config.LogPath
}
## If we want to insert a new line the append parameter is used.
elseif ($NewLine -eq "yes") {
$value | Out-File -Append -FilePath $Config.LogPath
}
}
## If the log file does not exist it is passed as a value
elseif (!(Test-path $Config.LogPath)) {
$value | Out-File -FilePath $Config.LogPath
}
}

Powershell replace content in file adds redundent carriage return

I have the following script that should be running from a cmd script:
powershell -command "(Get-Content %baseKitPathFile%) | ForEach-Object { $_ -replace 'Latest', '%version%' } | Set-Content %baseKitPathFile%"
The script is working fine and replacing the content of Latest to a version variable however it also adds carriage return after the end of the file
How can I search replace a text file content without the extra carriage return
maybe be trying to use [io.file]:
The most important is that if should be running from cmd script
Set-Content and Out-File both put a linebreak after each line, including the last one. To avoid that you must use an IO.File method:
powershell -Command "$txt = (Get-Content %baseKitPathFile%) -replace 'Latest', '%version%'; [IO.File]::WriteAllText('%baseKitPathFile%', $txt)"
A PowerShell script would be better to handle than the above commandline, though:
[CmdletBinding()]
Param(
[Parameter()][string]$Filename,
[Parameter()][string]$Version
)
$txt = (Get-Content $Filename) -replace 'Latest', $Version
[IO.File]::WriteAllText($Filename, $txt)
Call it like this:
powershell -File "C:\path\to\your.ps1" "%baseKitPathFile%" "%version%"

What's the easiest way to extract part of this line?

I am using PowerShell to insert data into a database but before I get to that step I need to pull the information from a log file. How can I extract the title of the project from this line in the log file?
1>Project "E:\Builds\1\IS_WSD\Lab1\src\Lab1.sln" on node 1 (default targets).
The title would be "Lab1.sln"
I already have (Get-Content C:\Users\myusername\Documents\Lab1.log)[1] which pulls this whole line but I need to narrow down even more.
How about a regex way:
$x = '1>Project "E:\Builds\1\IS_WSD\Lab1\src\Lab1.sln" on node 1 (default targets).'
$x -match '".*\\(.*)"'
$Matches[1]
or a not regex way:
$x.SubString($x.LastIndexOf('\')+1, ($x.LastIndexOf('"')-$x.LastIndexOf('\'))-1)
Do this:
$logfile = 'C:\Users\myusername\Documents\Lab1.log'
(Get-Content $logfile)[1] -replace '^.*?".*?\\([^\\]+)".*', '$1'
or this:
$logfile = 'C:\Users\myusername\Documents\Lab1.log'
(Get-Content $logfile)[1] -replace '^.*?"' -replace '".*$' -replace '^.*\\'

Foreach loop in Powershell on the console

Very simple question here, I want to see how can we process a bunch of commands using foreach on the command line (not through a PS1 script).
For instance, I display the directory listing on the console, now I want to execute 2 commands per object.
Get-ChildItem | ForEach-Object { Write-Host $_ $_}
This is ok, it shows the filename twice, but lets say I wanted to run 2 Write-Host commands for the same object, would that be possible on the console?
PS: I'm trying to achieve writing an output to 2 files using the out-file cmdlet, so I can read something and have 2 separate out-file calls per object
Thanks
you can script in the console windows just as you would in a powershell file. Use the "`" (backtick) key to separate lines. e.g.:
PS > Write-Host `
>>> hello, world!
So you could do
PS > Get-ChildItem | ForEach-Object { `
>>> Write-Host $_ `
>>> doFoo() `
>>> doBar() `
>>> ` }
Basically you want to execute 2 commands in ForEach-Object statement, right?
Just use ; to separate commands in this way ForEach-Object { command1; command2 }
In your code it should be something like this
Get-ChildItem | ForEach-Object { Write-Host $_; Write-Host $_ }