I'm trying to edit the contents of a config file called prefs.cfg. It has two lines:
Server.Name "test"
VoIP.Enabled "1"
I'm trying to get more comfortable with replacing string but I seem to keep messing up.
I wrote something out, I would appreciate if someone could point in my script where I'm going wrong .
$prefs = Get-Content .\prefs.cfg
$prefs | Select-String "Server.Name"
$servername = Read-Host -Prompt "Enter Server Name"
Write-Host $servername
$prefs -replace $servername
$prefs
Although you are passing $prefs to Select-String and -replace, the results of those operations are not being assigned to variables. So you cannot use them later.
One argument is being passed to -replace. It expects two: what to replace, and what to replace it with. Edit: if a single argument is provided, this is taken as "what to replace". As "what to replace it with" is not provided, it will be replaced with nothing (i.e. deleted)
Select-String and -replace use regex. Seems a bit overkill for this task. Where-Object and .Replace are perfectly up to the task.
$prefs = Get-Content .\prefs.cfg
# Get the line using Where. * is wildcard
$oldServerLine = $prefs | Where-object {$_ -like "Server.Name*"}
$servername = Read-Host -Prompt "Enter Server Name"
Write-Host $servername
# Replace old line with new line. ` is the escape character so you get " as expected.
$newPrefs = $prefs.Replace($oldServerLine,"Server.Name `"$servername`"")
$newPrefs
Related: difference between -replace and .Replace
Related
This question already has answers here:
How can you use an object's property in a double-quoted string?
(5 answers)
Closed 5 months ago.
I wrote a script that allows me to query the whole Azure database park:
#$ErrorActionPreference = 'SilentlyContinue'
# Connect to Azure
$azureAccount = Connect-AzAccount
# Get Azure Access Token (we will use this to query the databasees)
#$azureToken = Get-AzAccessToken -ResourceUrl https://database.windows.net
$access_token = (Get-AzAccessToken -ResourceUrl https://database.windows.net).Token
# Queries will be picked up from here
$folderPath = '.\Queries'
# Choose how to format each date ("yyyy-MM-dd") or ("yyyy-MM-dd HH:mm:ss")
$DateTime = (Get-Date).ToString("yyyy-MM-dd")
# List Azure Sunscriptions
Get-Azsubscription | ForEach-Object -Begin { $a = 1 } -Process {"$a $($_.Name)"; $a++}
$SubscriptionChoice = Read-Host -Prompt "Copy/paste the name of the Subscription that you want to investigate. If more than one separate them by a coma, Type `"All`" if you want to target all of them"
# Iterate into subscriptoins and print names
foreach ($gs in $SubscriptionChoice) {
Select-Azsubscription -Subscription "$gs" | Out-Null
Write-Host "Let's browse into Azure Sunscription: " -NoNewline
Write-Host (Get-AzContext).Subscription.Name -ForegroundColor green
# Fins all Azure SQL Server
Get-AzSqlServer | ForEach-Object -Begin { $a = 1 } -Process {"$a $($_.ServerName)"; $a++}
$SqlServerChoice = Read-Host -Prompt "Copy/paste the name of the SQL Server that you want to investigate. If more than one separate them by a coma, Type `"All`" if you want to target all of them"
if ($SqlServerChoice = "All"){
$SqlServerChoice = Get-AzSqlServer
}
Foreach ($server in $SqlServerChoice){
$DatabaseChoice = Get-AzSqlDatabase -ServerName $server.ServerName -ResourceGroupName $server.ResourceGroupName | Where-Object DatabaseName -NE "master"
Foreach ($database in $DatabaseChoice){
(Get-ChildItem $folderPath | sort-object {if (($i = $_.BaseName -as [int])) {$i} else {$_}} ).Foreach{
Invoke-Sqlcmd -ServerInstance $server.FullyQualifiedDomainName -Database $database.DatabaseName -AccessToken $access_token -InputFile $psitem.FullName | Export-Csv -Path ".\Results\$psitem.csv" -Append -NoTypeInformation
write-host "Executing $psitem on $database.DatabaseName"
}
}
}
}
However each time the query is executed against a database the Write-Hosts returns:
Executing DTU_to_vCore.sql on Microsoft.Azure.Commands.Sql.Database.Model.AzureSqlDatabaseModel.DatabaseName
Here a picture:
This Write-Hosts comes from the line:
write-host "Executing $psitem on $database.DatabaseName"
In which you can find the two variables:
$psitem : which is the name of the file that contains the query
$database.DatabaseName : which should be the database name but instead of printing the database name is printing Microsoft.Azure.Commands.Sql.Database.Model.AzureSqlDatabaseModel.DatabaseName
Why one of the two variable is not interpreted?
You need to encapsulate your variable property in a subexpression operator $().
write-host "Executing $psitem on $($database.DatabaseName)"
This is because only simple variables get expanded in an expandable string.
References
Only simple variable references can be directly embedded in an
expandable string. Variables references using array indexing or member
access must be enclosed in a subexpression.
Source: about_Quoting_Rules
Subexpression operator $( )
Returns the result of one or more statements. For a single result,
returns a scalar. For multiple results, returns an array. Use this
when you want to use an expression within another expression. For
example, to embed the results of command in a string expression.
PS> "Today is $(Get-Date)"
Today is 12/02/2019 13:15:20
PS> "Folder list: $((dir c:\ -dir).Name -join ', ')"
Folder list: Program Files, Program Files (x86), Users, Windows
Source: about_Operators
foreach ($Target in $TargetUSBs)
{
$LogPath= #"
$SourceUSB\$(((Get-CimInstance -ClassName Win32_volume)|where {$_.DriveType -eq "2" -and $_.DriveLetter -eq $Target}).SerialNumber)_
$(((Get-CimInstance -ClassName Win32_OperatingSystem).LocalDateTime).Year)$(((Get-CimInstance -ClassName Win32_OperatingSystem).LocalDateTime).Month)
$(((Get-CimInstance -ClassName Win32_OperatingSystem).LocalDateTime).Day)_$(((Get-CimInstance -ClassName Win32_OperatingSystem).LocalDateTime).Hour)
$(((Get-CimInstance -ClassName Win32_OperatingSystem).LocalDateTime).Minute)$(((Get-CimInstance -ClassName Win32_OperatingSystem).LocalDateTime).Second).txt
"#
$LogPath = $LogPath.Replace("`n","").Trim()
New-item -Path "$LogPath"
}
The Irony is when I copy and paste the contents of my variable and manually create a new-item -path and paste said contents it works but when I use the variable it does not...
Brief summary of my goal I am taking a USB labelled ORIGINAL and obtaining the S/N of every USB plugged in at the time and creating separate log files for each with the title consisting of SERIALNUMBER_DATE_TIME.txt and these files are created in ORIGINAL USB
$LogPath contains for example the following: E:\Mattel\1949721369_2018912_93427.txt
Yet when I use the Variable in New-item it indicates "Illegal characters in Path"
FYI $LogPath is a System.String not an object
$TargetUSBs is filled with all USB drives plugged into the system
this method of using a variable for a path usually works fine for me only difference is the here-string I used this time around does this cause my problem? I hope not because I really don't want to fill that variable all on one line. New-Item's helpfiles shows <String[]> for -path parameter does this mean I have to use a string array? and if so how do I convert this to make this work?
Your problem is that Windows uses CRLF line endings (Unix only LF), so you still have CR chars in your path.
To fix this just use:
.Replace("`r`n","")
However you can easily simplify your code so you do not require the messy here-string or replace/trim...
By using a single Get-Date call you can format it to your desired output. This means you can just build the Path as a simple string and involves much less code:
foreach ($Target in $TargetUSBs)
{
$SerialNumber = Get-CimInstance -ClassName Win32_volume | where {$_.DriveType -eq "2" -and $_.DriveLetter -eq $Target} | Select-Object -ExpandProperty SerialNumber
$DateTime = Get-Date -Format "yyyyMd_Hms"
New-item -Path "$SourceUSB\$SerialNumber_$DateTime.txt"
}
I have a script that I have wrote that reaches out to a remote machine or the local machine and grabs the environment variables and puts them into a file.
the issue is I have Internal and External hosts. Each hostname would end in either INT or EXT. if the command runs on any host that has EXT in the name it will need to be supplied with my PSCredential object. all other hosts wont work if credentials are used.
My issue is how to determine if the hostname has "EXT"in the name or not.
if i put the below into ISE it gives me a true/false and works fine,
But if that variable is being populated from a parameter when the script is called $test end up being what ever the hostname that was entered.
$compuername = "HOSTNAME1ext"
$test = $compuername -like "*ext"
if ($test -eq $true) {Write-Host "yes"} else {Write-Host "no"}
yes
But when it is used like this it does not work
[cmdletbinding()]
param(
[Parameter(Mandatory=$true)]
[string[]]$ComputerName = $env:ComputerName,
[string]$Name
)
$test = $ComputerName -like "*ext"
if ($test -eq $true) {
$UNPASSWORD = Get-Credential -UserName "$ComputerName\ACCOUNT" -message "Enter the Password for the ACCOUNT Account";$EnvObj = #(Get-WMIObject -Class Win32_Environment -ComputerName $ComputerName -Credential $UNPASSWORD -EA Stop)
} else {$EnvObj = #(Get-WMIObject -Class Win32_Environment -ComputerName $ComputerName -EA Stop)}
when this is done $test comes back as the hostname entered rather than True or False.
When you apply the -like operator to a collection of objects, in your example an array of strings, if works as a filter operator - ie. it only returns the items that satisfy the condition.
Either change the parameter type:
[Parameter(Mandatory=$true)]
[string]$ComputerName
or connect to each computer one by one:
foreach($Name in $ComputerName){
if($Name -like '*ext'){
# Ask for Credential
}
}
Trying to build a link with a variable and a string, but I always get a space in between them. How can I fix this?
The $sub is a SPWeb object from sharepoint.
Write-Host $sub.Url "/default.aspx"
result:
https://intra.mycompany/pages/sales /default.aspx
Put the $sub variable inside the string literal so that it is treated as one string:
Write-Host "$($sub.Url)/default.aspx"
Note that you will need to use a sub expression operator $(...) since you are accessing an attribute of $sub.
Another approach, depending on how complicated your string is, is to use the -f format operator:
Write-Host ("{0}/default.aspx" -f $sub.Url)
If you have many variables that you need to insert, it can make for cleaner and easier to read code.
Use the URL class' constructor to do the join, rather than using string manipulation. This will have the additional advantage of automatically take care of appending any slashes required.
function Join-Uri {
[CmdletBinding()]
param (
[Alias('Path','BaseUri')] #aliases so naming is consistent with Join-Path and .Net's constructor
[Parameter(Mandatory)]
[System.Uri]$Uri
,
[Alias('ChildPath')] #alias so naming is consistent with Join-Path
[Parameter(Mandatory,ValueFromPipeline)]
[string]$RelativeUri
)
process {
(New-Object -TypeName 'System.Uri' -ArgumentList $Uri,$RelativeUri)
#the above returns a URI object; if we only want the string:
#(New-Object -TypeName 'System.Uri' -ArgumentList $Uri,$RelativeUri).AbsoluteUri
}
}
$sub = new-object -TypeName PSObject -Property #{Url='http://demo'}
write-host 'Basic Demo' -ForegroundColor 'cyan'
write-host (Join-Uri $sub.Url '/default.aspx')
write-host (Join-Uri $sub.Url 'default.aspx') #NB: above we included the leading slash; here we don't; yet the output's consistent
#you can also easily do this en-masse; e.g.
write-host 'Extended Demo' -ForegroundColor 'cyan'
#('default.aspx','index.htm','helloWorld.aspx') | Join-Uri $sub.Url | select-object -ExpandProperty AbsoluteUri
Above I created a function to wrap up this functionality; but you could just as easily do something such as below:
[string]$url = (new-object -TypeName 'System.Uri' -ArgumentList ([System.Uri]'http://test'),'me').AbsoluteUri
Link to related documentation: https://msdn.microsoft.com/en-us/library/9hst1w91(v=vs.110).aspx
I'm pretty familiar with PHP, Javascript, etc but I'm new to Powershell. I'm trying to get IP addresses and Mac addresses from all the computer's in an active directory. I came across a script that gets an object with all the computer names a lists them through a foreach loop. Inside that loop, I'm trying to run the following:
$colItems = GWMI -cl "Win32_NetworkAdapterConfiguration" -name "root\CimV2" `
comp $objComputer.name -filter "IpEnabled = TRUE"
Obviously, this isn't working since it can't take data from the pipeline. Is there away to take the name property and convert it into a string variable to use within the Get-WmiObject? I've tried declaring a string variable with that $objComputer.name as the value and tried $($objComputer.name), but neither did it for me. Any help would be greatly appreciated.
i think you need a hyphen in front of comp...
$colItems = GWMI -cl "Win32_NetworkAdapterConfiguration" -name "root\CimV2" -comp $objComputer.name -filter "IpEnabled = TRUE"
that could be a copy and paste error...
This works for me though (using a dot):
$colItems =GWMI -cl "Win32_NetworkAdapterConfiguration" -name "root\CimV2" -comp . -filter "IpEnabled = TRUE"
using $objComputer though you could do this
$objComputer = #{ "name" = "." }
Matt
Unfortunately Get-WmiObject doesn't accept pipeline input. Altough passing $objComputer.name is perfectly valid (as long as $objComputer is an object that has a name member) you can assign the name value to a vraible and pass the variable to the ComputerName property.
foreach($objComputer $computers)
{
$name = $objComputer.name
$colItems = GWMI -cl Win32_NetworkAdapterConfiguration -comp $name -filter "IpEnabled = TRUE"
$colItems
...
}