Powershell Add Spaces to Registry Data Output - variables

I'm trying to create a small script, that can easily display some valid information to the standard user in regards of getting IT assistance from ServiceDesk.
Current output
So to improve this i was trying to figure out if i could add spaces to the teamviewer result.
This is an example of the current team viewer ID outcome:
1483547869
But i would like if the outcome could be:
1 483 547 869
This is a small thing but it will make it a lot easier to read for the standard user.
This is my code:
Add-Type -AssemblyName System.Windows.Forms
$ip=get-WmiObject Win32_NetworkAdapterConfiguration|Where {$_.Ipaddress.length -gt 1}
$ipaddress = $ip.ipaddress[0]
$hostname = [System.Net.Dns]::GetHostName()
$TeamViewerVersions = #('10','11','12','13','14','')
If([IntPtr]::Size -eq 4) {
$RegPath='HKLM:\SOFTWARE\TeamViewer'
} else {
$RegPath='HKLM:\SOFTWARE\Wow6432Node\TeamViewer'
}
$ErrorActionPreference= 'silentlycontinue'
foreach ($TeamViewerVersion in $TeamViewerVersions) {
If ((Get-Item -Path $RegPath$TeamViewerVersion).GetValue('ClientID') -ne $null) {
$TeamViewerID=(Get-Item -Path $RegPath$TeamViewerVersion).GetValue('ClientID')
}
}
$msgBoxInput = [System.Windows.Forms.MessageBox]::Show("Computer Name: $hostname`nIP Address: $ipaddress`nTeamViewer ID: $TeamviewerID`n`nWould you like to open Self Service Portal?", 'Quick Support','YesNo','Information')
If ($msgBoxInput -eq 'Yes' ){
start https://www.google.com/
Else
}
Stop-Process -Id $PID

Here's a really simple solution to format a number:
$TeamViewerDisplayID = $TeamViewerID.toString("### ### ### ###")
This will display 1483547869 as 1 483 547 869. Note: if your number will have 9 characters for example, the above line of code will add a space to the beginning. Example: "483547869" becomes "_483 547 869". So if you want, you can add another if statement there that checks how long the number is and formats it accordingly:
if ($TeamViewerID.length -gt 9) {
$TeamViewerID.toString("### ### ### ###")
} else {
$TeamViewerID.toString("### ### ###")
}

Related

PowerShell to remove matching line plus immediately following line

I am trying to convert a “sed” script I use on my FreeBSD machine to one using “Powershell” on Windows 10.
This is the sed script. It is used to strip a header from an email plus the immediately following line and send the output to “email_1.txt”. The file is fed to the script on the command line; i.e. “COMMAND file”
sed '/Received: by 2002:a17:90a:3566:0:0:0:0/,/^/d' <$1> email_1.txt
I cannot find a way to get this to work with “PowerShell”.
Thanks!
You have a couple of options.
Install sed -
Something like scoop might be helpful here.
Write a pure powershell solution.
This will be very similar to what you would write if you were to try to do the same thing in "pure" bash. Here is an attempt to do so:
--
function Delete-TargetLines {
[cmdletbinding()]
param(
[String]$needle,
[int]$count = [int]1,
[parameter(ValueFromPipeline)]
[string[]]$haystack
)
Begin {
[int]$seen = 0
}
Process {
if ($seen -gt 0) {
$seen -= 1
} elseif ( $haystack -match $needle ) {
$seen = 1
} else {
$haystack
}
}
}
And an example of running it:
> #("Pre-line", "This is a test", "second line", "post line") | Delete-TargetLines -needle "test"
Pre-line
post line
> Get-Content $myfile | Delete-TargetLines -needle 'value' > $outfile

Using PowerShell, how can a SQL file be split into several files based on its content?

I'm trying to use PowerShell to automate the division of a SQL file into seperate files based on where the headings are located.
An example SQL file to be split is below:
/****************************************
Section 1
****************************************/
Select 1
/****************************************
Section 2
****************************************/
Select 2
/****************************************
Section 3
****************************************/
Select 3
I want the new files to be named as per the section headings in the file i.e. 'Section 1', 'Section 2' and 'Section 3'. The content of the first file should be as follows:
/****************************************
Section 1
****************************************/
Select 1
The string: /**************************************** is only used in the SQL file for the section headings and therefore can be used to identify the start of a section. The file name will always be the text on the line directly below.
You can try like this (split is here based on empty lines between sections) :
#create an index for our output files
$fileIndex = 1
#load SQLite file contents in an array
$sqlite = Get-Content "G:\input\sqlite.txt"
#for each line of the SQLite file
$sqlite | % {
if($_ -eq "") {
#if the line is empty, increment output file index to create a new file
$fileindex++
} else {
#if the line is not empty
#build output path
$outFile = "G:\output\section$fileindex.txt"
#push line to the current output file (appending to existing contents)
$_ | Out-File $outFile -Append
}
}
#load generated files in an array
$tempfiles = Get-ChildItem "G:\output"
#for each file
$tempfiles | % {
#load file contents in an array
$data = Get-Content $_.FullName
#rename file after second line contents
Rename-Item $_.FullName "$($data[1]).txt"
}
The below code uses the heading names found within the comment blocks. It also splits the SQL file into several SQL files based on the location of the comment blocks.
#load SQL file contents in an array
$SQL = Get-Content "U:\Test\FileToSplit.sql"
$OutputPath = "U:\TestOutput"
#find first section name and count number of sections
$sectioncounter = 0
$checkcounter = 0
$filenames = #()
$SQL | % {
#Add file name to array if new section was found on the previous line
If ($checkcounter -lt $sectioncounter)
{
$filenames += $_
$checkcounter = $sectioncounter
}
Else
{
If ($_.StartsWith("/*"))
{
$sectioncounter += 1
}
}
}
#return if too many sections were found
If ($sectioncounter > 50) { return "Too many sections found"}
$sectioncounter = 0
$endcommentcounter = 0
#for each line of the SQL file (Ref: sodawillow)
$SQL | % {
#if new comment block is found point to next section name, unless its the start of the first section
If ($_.StartsWith("/*") -And ($endcommentcounter -gt 0))
{
$sectioncounter += 1
}
If ($_.EndsWith("*/"))
{
$endcommentcounter += 1
}
#build output path
$tempfilename = $filenames[$sectioncounter]
$outFile = "$OutputPath\$tempfilename.sql"
#push line to the current output file (appending to existing contents)
$_ | Out-File $outFile -Append
}

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.

parsing text-files in powershell with where and select-string operators

recently I had to solve a problem reading a large amount of logfiles and picking specific chunks of text out of them.
With some trial and error I found a working solution but I'd like to know if there are better approaches.
These logfiles contain text-blocks, each is introduced by a 'heading' followed by an unknown amount of entries and finished with an empty line. (Example below, the numbers are pseudo linenumbers)
35# logevent1
36# entry1
37# entry2
38# entry3
39#
40# logevent2
41# entry1
42# entry2
Thus I know the 'logevent'-tag I can retrieve the line with $line = $logfile | Select-String -Pattern 'logevent1' and with $lineNumber = $line | Select-Object -ExpandProperty LineNumber I have the first value to use Get-Content with range operator [$x..$y].
In my example this would be 35. But how do I get the first empty line behind the text block?
I tried to work with Select-String -Pattern '' but that gives an instant exception due to the string is empty. So I wrote he following function:
function Get-TextBlock([string]$filePath,$lineNumber)
{
$startLine = ($lineNumber -1)
$counter = 0
$emptyLines = #()
Get-Content (Get-ChildItem $filePath) | ForEach-Object {
if( $_ -eq '' ) {
$emptyLines += $counter;
}
$counter++
}
$endLine = 0
$counter = 0
while( $endLine -le $startLine) {
$endLine = ($emptyLines[$counter]); $counter++;
}
$output += ((Get-ChildItem $filePath) | Get-Content)[$startLine..$endLine]
return $output
}
As mentioned before the function works for me but I feel like there are much better and easier ways to perfrom this task.
The Output (after removing my pseudo-line-numbers ;) ) looks like this
PS F:\scripts\powershell> Get-TextBlock '.\function-test.txt' 35
logevent1
entry1
entry2
entry3
____________________________________________________________________________
Kind regards

Powershell using file? "being used by another process"

I have this powershell script running. The first time it runs it runs flawlessly, the second time it runs i get the error that the .csv cannont be access "because it is being used by another process. Any idea which part of the script is "holding onto" the file and how i can make it let it go at the end?
clear
set-executionpolicy remotesigned
# change this to the directory that the script is sitting in
cd d:\directory
#############################################
# Saves usernames/accountNumbers into array #
# and creates sql file for writing to #
#############################################
# This is the location of the text file containing accounts
$accountNumbers = (Get-Content input.txt) | Sort-Object
$accountID=0
$numAccounts = $accountNumbers.Count
$outString =$null
# the name of the sql file containing the query
$file = New-Item -ItemType file -name sql.sql -Force
###################################
# Load SqlServerProviderSnapin100 #
###################################
if (!(Get-PSSnapin | ?{$_.name -eq 'SqlServerProviderSnapin110'}))
{
if(Get-PSSnapin -registered | ?{$_.name -eq 'SqlServerProviderSnapin110'})
{
add-pssnapin SqlServerProviderSnapin100
Write-host SQL Server Provider Snapin Loaded
}
else
{
}
}
else
{
Write-host SQL Server Provider Snapin was already loaded
}
#################################
# Load SqlServerCmdletSnapin100 #
#################################
if (!(Get-PSSnapin | ?{$_.name -eq 'SqlServerCmdletSnapin100'}))
{
if(Get-PSSnapin -registered | ?{$_.name -eq 'SqlServerCmdletSnapin100'})
{
add-pssnapin SqlServerCmdletSnapin100
Write-host SQL Server Cmdlet Snapin Loaded
}
else
{
}
}
else
{
Write-host SQL Server CMDlet Snapin was already loaded
}
####################
# Create SQL query #
####################
# This part of the query is COMPLETELY static. What is put in here will not change. It will usually end with either % or '
$outString = "SELECT stuff FROM table LIKE '%"
# Statement ends at '. loop adds in "xxx' or like 'xxx"
IF ($numAccounts -gt 0)
{
For ($i =1; $i -le ($AccountNumbers.Count - 1); $i++)
{
$outString = $outstring + $AccountNumbers[$accountID]
$outString = $outString + "' OR ca.accountnumber LIKE '"
$accountID++
}
$outString = $outString + $AccountNumbers[$AccountNumbers.Count - 1]
}
else
{
$outString = $outString + $AccountNumbers
}
# This is the end of the query. This is also COMPLETELY static. usually starts with either % or '
$outString = $outString + "%'more sql stuff"
add-content $file $outString
Write-host Sql query dynamically written and saved to file
###########################
# Create CSV to email out #
###########################
#Make sure to point it to the correct input file (sql query made above) and correct output csv.
Invoke-Sqlcmd -ServerInstance instance -Database database -Username username -Password password -InputFile sql.sql | Export-Csv -Path output.csv
####################################
# Email the CSV to selected people #
####################################
$emailFrom = "to"
$emailTo = "from"
$subject = "test"
$body = "test"
$smtpServer = "server"
# Point this to the correct csv created above
$filename = "output.csv"
$att = new-object Net.mail.attachment($filename)
$msg = new-object net.mail.mailmessage
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$msg.from = $emailFrom
$msg.to.add($emailto)
$msg.subject = $subject
$msg.body = $body
$msg.attachments.add($att)
$smtp.Send($msg)
Can you try to add at th end :
$att.Dispose()
$msg.Dispose()
$smtp.Dispose()
You could also try and use a tool like procmon and see what does the script do whenever it acquires a lock on the file and doesn't release it. Also, since (supposedly) the problem is with the .csv file, you could load it as byte array instead of passing it's path as an attachment. This way the file should be read once and not locked.